diff --git a/api/ambil_dataOLT.php b/api/ambil_dataOLT.php
new file mode 100644
index 0000000..716111f
--- /dev/null
+++ b/api/ambil_dataOLT.php
@@ -0,0 +1,117 @@
+getConnection();
+
+// ================= CONFIG =================
+$login_url = "http://10.255.254.21/login";
+$data_url = "http://10.255.254.21/ontinfo_table";
+
+$username = "root";
+$password = "@lokal234";
+
+$cookie = __DIR__ . "/cookie.txt";
+
+// ================= LOGIN =================
+$ch = curl_init();
+curl_setopt($ch, CURLOPT_URL, $login_url);
+curl_setopt($ch, CURLOPT_POST, true);
+curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
+ "username" => $username,
+ "password" => $password
+]));
+curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie);
+curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie);
+curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
+curl_exec($ch);
+curl_close($ch);
+
+// ================= AMBIL DATA =================
+$ch = curl_init();
+curl_setopt($ch, CURLOPT_URL, $data_url);
+curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie);
+curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
+
+$response = curl_exec($ch);
+
+if ($response === false) {
+ die("CURL ERROR: " . curl_error($ch));
+}
+curl_close($ch);
+
+file_put_contents("debug_onu.json", $response);
+
+$data = json_decode($response, true);
+
+if (!isset($data['data']) || empty($data['data'])) {
+ die("DATA KOSONG");
+}
+
+// ================= PROCESS =================
+foreach ($data['data'] as $onu) {
+
+ $sn = $onu['ont_sn'] ?? '';
+ $rx = $onu['receive_power'] ?? 0;
+ $state = $onu['state'] ?? 0;
+ $cause = strtolower($onu['last_d_cause'] ?? '');
+
+ if (empty($sn)) continue;
+
+ // ================= STATUS =================
+ if (strpos($cause, 'laser out') !== false || strpos($cause, 'fiber') !== false) {
+ $status = "LASER OUT";
+ } elseif (strpos($cause, 'power down') !== false || strpos($cause, 'dying-gasp') !== false) {
+ $status = "POWER FAIL";
+ } else {
+ if ($state == 0 && $rx <= -30) {
+ $status = "LASER OUT";
+ } elseif ($rx <= -30) {
+ $status = "POWER FAIL";
+ } else {
+ $status = "ONLINE";
+ }
+ }
+
+ // ================= GET LAST STATUS =================
+ $cek = $conn->prepare("SELECT status FROM onu_status WHERE sn = ?");
+ $cek->execute([$sn]);
+ $last = $cek->fetch(PDO::FETCH_ASSOC);
+ $lastStatus = $last['status'] ?? null;
+
+ // ================= UPSERT REALTIME =================
+ $conn->query("
+ INSERT INTO onu_status (sn, status, rx_power, last_update)
+ VALUES ('$sn', '$status', '$rx', NOW())
+ ON DUPLICATE KEY UPDATE
+ last_status = status,
+ status = '$status',
+ rx_power = '$rx',
+ last_update = NOW()
+ ");
+
+ // ================= LOG HISTORI (HANYA ANOMALI) =================
+ $anomali = in_array($status, ['LASER OUT', 'POWER FAIL']);
+
+ $trigger = ($lastStatus !== $status);
+
+ if ($anomali && $trigger) {
+
+ $stmt = $conn->prepare("
+ INSERT INTO status_onu_histori (sn, status, rx_power, created_at)
+ VALUES (?, ?, ?, NOW())
+ ");
+ $stmt->execute([$sn, $status, $rx]);
+
+ echo "LOG ANOMALI: $sn | $status | RX $rx
";
+ }
+
+ echo "SN: $sn | STATUS: $status | RX: $rx
";
+}
+
+echo "DONE ✅";
+?>
\ No newline at end of file
diff --git a/api/auto_notif_device.php b/api/auto_notif_device.php
new file mode 100644
index 0000000..4f8443f
--- /dev/null
+++ b/api/auto_notif_device.php
@@ -0,0 +1,369 @@
+getConnection();
+
+// 🔥 GROUP TEKNISI
+$groupTeknisi = "120363427232707228@g.us";
+
+// ======================
+// 🔥 FUNCTION WA
+// ======================
+if (!function_exists('kirimWA')) {
+function kirimWA($target, $pesan) {
+ if (!$target) return;
+
+ $token = "XjC9oSr4jECWG93JQRWf";
+
+ $data = [
+ "target" => $target,
+ "message" => $pesan,
+ ];
+
+ $curl = curl_init();
+
+ curl_setopt_array($curl, [
+ CURLOPT_URL => "https://api.fonnte.com/send",
+ CURLOPT_RETURNTRANSFER => true,
+ CURLOPT_POST => true,
+ CURLOPT_POSTFIELDS => http_build_query($data),
+ CURLOPT_HTTPHEADER => [
+ "Authorization: $token"
+ ],
+ CURLOPT_TIMEOUT => 10
+ ]);
+
+ curl_exec($curl);
+ curl_close($curl);
+}
+}
+
+// ======================
+// 🔥 TEST MODE (OPSIONAL)
+// ======================
+$TEST_MODE = false;
+
+// ======================
+// 🔥 AMBIL DATA DARI DATABASE (JOIN HISTORY)
+// ======================
+$stmt = $conn->query("
+SELECT
+ f.id,
+ f.name,
+ f.sn_onu,
+ f.latitude,
+ f.longitude,
+ f.customer_phone,
+
+ o.rx_power,
+ o.voltage,
+ o.updated_at
+
+FROM ftth_items f
+
+LEFT JOIN (
+ SELECT h1.*
+ FROM onu_daily_history h1
+ INNER JOIN (
+ SELECT sn, MAX(updated_at) AS max_time
+ FROM onu_daily_history
+ WHERE DATE(updated_at) = CURDATE()
+ GROUP BY sn
+ ) h2
+ ON h1.sn = h2.sn
+ AND h1.updated_at = h2.max_time
+) o
+ ON o.sn = f.sn_onu
+
+INNER JOIN item_types it
+ ON it.id = f.item_type_id
+
+WHERE f.sn_onu IS NOT NULL
+ AND LOWER(it.name) = 'pelanggan'
+");
+
+$dataItems = $stmt->fetchAll(PDO::FETCH_ASSOC);
+
+foreach ($dataItems as $item) {
+
+ usleep(200000);
+
+ $sn = strtoupper(trim($item['sn_onu']));
+ $nama = $item['name'];
+ $lat = $item['latitude'];
+ $lng = $item['longitude'];
+ $phone = $item['customer_phone'];
+
+ // ======================
+ // 🔥 AMBIL RX & VOLT DARI DB
+ // ======================
+ $rx = isset($item['rx_power']) ? floatval($item['rx_power']) : null;
+ $volt = isset($item['voltage']) ? floatval($item['voltage']) : null;
+
+ if ($rx === null && $volt === null) {
+ continue;
+ }
+
+ // ======================
+ // 🔥 STATUS DETEKSI
+ // ======================
+// RX NORMAL = -20 s/d -25.99 dBm
+
+$isRxHighLoss = ($rx !== null && $rx < -25.99); // redaman terlalu besar
+$isRxLowLoss = ($rx !== null && $rx > -20.00); // redaman terlalu kecil
+
+$isBadRx = $isRxHighLoss || $isRxLowLoss;
+
+
+// VOLTAGE NORMAL = 3.20 - 3.29 V
+
+$isVoltLow = ($volt !== null && $volt < 3.20);
+$isVoltHigh = ($volt !== null && $volt > 3.29);
+
+$isBadVolt = $isVoltLow || $isVoltHigh;
+
+
+// ======================
+// 🔥 KETERANGAN ANALISA
+// ======================
+
+$rxKeterangan = '';
+
+if ($isRxHighLoss) {
+
+ $rxKeterangan =
+ "Redaman terlalu besar (High Loss). Sinyal optik berada di bawah standar perusahaan. Kemungkinan terjadi redaman berlebih pada jalur fiber, sambungan, konektor, splitter, atau kabel mengalami kerusakan.";
+
+} elseif ($isRxLowLoss) {
+
+ $rxKeterangan =
+ "Redaman terlalu kecil (Low Loss). Nilai sinyal optik berada di atas standar perusahaan. Diperlukan pengecekan kualitas distribusi jaringan dan konfigurasi perangkat.";
+}
+
+$voltKeterangan = '';
+
+if ($isVoltLow) {
+
+ $voltKeterangan =
+ "Tegangan ONU berada di bawah standar 3.20 - 3.29 Volt. Kemungkinan adaptor lemah, kabel power rusak, atau suplai listrik tidak stabil.";
+
+} elseif ($isVoltHigh) {
+
+ $voltKeterangan =
+ "Tegangan ONU berada di atas standar 3.20 - 3.29 Volt. Diperlukan pengecekan adaptor dan sumber daya listrik.";
+}
+
+
+ // ======================
+ // 🔥 CEK ANTI SPAM LOG
+ // ======================
+ $cek = $conn->prepare("
+ SELECT last_rx, last_voltage
+ FROM notif_device_log
+ WHERE sn = ?
+ ");
+ $cek->execute([$sn]);
+ $last = $cek->fetch(PDO::FETCH_ASSOC);
+
+ $lastRx = $last['last_rx'] ?? null;
+ $lastVolt = $last['last_voltage'] ?? null;
+
+ $isChanged =
+ round((float)$lastRx, 2) != round((float)$rx, 2) ||
+ round((float)$lastVolt, 2) != round((float)$volt, 2);
+
+ if (!$isChanged) {
+ continue;
+ }
+
+ // ======================
+ // 🔥 MAPS
+ // ======================
+ $maps = ($lat && $lng)
+ ? "https://www.google.com/maps?q={$lat},{$lng}"
+ : "-";
+
+ // ======================
+ // 🔥 FORMAT NOMOR
+ // ======================
+ $phoneFix = null;
+ if ($phone) {
+ $phoneFix = preg_replace('/[^0-9]/', '', $phone);
+ if (substr($phoneFix, 0, 1) == '0') {
+ $phoneFix = '62' . substr($phoneFix, 1);
+ }
+ }
+//$isBadVolt = ($volt !== null && $volt < 3.29);
+//$isVoltLow = ($volt !== null && $volt < 3.20);
+//$isVoltHigh = ($volt !== null && $volt > 3.29);
+
+//$isBadVolt = $isVoltLow || $isVoltHigh;
+
+
+// ======================
+// 🔥 NOTIFIKASI
+// ======================
+
+if ($isBadRx && $isBadVolt) {
+
+ // ======================
+ // PELANGGAN
+ // ======================
+
+ kirimWA(
+ $phoneFix,
+
+ "🚨 *Pemberitahuan Gangguan Layanan Internet*\n\n".
+
+ "Yth. {$nama},\n\n".
+
+ "Sistem monitoring kami mendeteksi kondisi jaringan dan perangkat internet di lokasi Anda berada di luar standar operasional.\n\n".
+
+ "📉 Kualitas Sinyal : ".number_format($rx,2)." dBm\n".
+ "🔌 Tegangan ONU : ".number_format($volt,2)." V\n\n".
+
+ "Gangguan ini berpotensi menyebabkan internet lambat, putus-putus, atau tidak dapat digunakan.\n\n".
+
+ "Tim teknis kami telah menerima laporan otomatis dan akan melakukan pengecekan lebih lanjut.\n\n".
+
+ "Mohon maaf atas ketidaknyamanan ini.\n\n".
+
+ "Terima kasih.\n".
+ "RockNet NOC"
+ );
+
+ // ======================
+ // TEKNISI
+ // ======================
+
+ kirimWA(
+ $groupTeknisi,
+
+ "🚨 *ANOMALI RX + VOLTAGE*\n\n".
+
+ "👤 Pelanggan : {$nama}\n".
+ "🔢 SN ONU : {$sn}\n\n".
+
+ "📉 RX Power : ".number_format($rx,2)." dBm\n".
+ "🔌 Voltage : ".number_format($volt,2)." V\n\n".
+
+ "📋 Analisa RX :\n".
+ "{$rxKeterangan}\n\n".
+
+ "📋 Analisa Voltage :\n".
+ "{$voltKeterangan}\n\n".
+
+ "📍 Lokasi :\n{$maps}\n\n".
+
+ "⚠ PRIORITAS TINGGI\n".
+ "Perlu pengecekan jalur fiber dan perangkat ONU."
+ );
+
+}
+elseif ($isBadRx) {
+
+ kirimWA(
+ $phoneFix,
+
+ "🚨 *Pemberitahuan Gangguan Jaringan*\n\n".
+
+ "Yth. {$nama},\n\n".
+
+ "Sistem monitoring mendeteksi kualitas sinyal fiber optik di lokasi Anda berada di luar standar operasional.\n\n".
+
+ "📉 Nilai Sinyal : ".number_format($rx,2)." dBm\n\n".
+
+ "Gangguan ini dapat menyebabkan internet tidak stabil, lambat, atau terputus.\n\n".
+
+ "Tim teknis kami telah menerima laporan otomatis dan akan melakukan pengecekan.\n\n".
+
+ "Mohon maaf atas ketidaknyamanan ini.\n\n".
+
+ "RockNet NOC"
+ );
+
+ kirimWA(
+ $groupTeknisi,
+
+ "🚨 *ANOMALI REDAMAN ONU*\n\n".
+
+ "👤 Pelanggan : {$nama}\n".
+ "🔢 SN ONU : {$sn}\n\n".
+
+ "📉 RX Power : ".number_format($rx,2)." dBm\n\n".
+
+ "📋 Analisa :\n".
+ "{$rxKeterangan}\n\n".
+
+ "📍 Lokasi :\n{$maps}\n\n".
+
+ "🔧 Perlu pengecekan jalur fiber, konektor, splitter dan sambungan."
+ );
+
+}
+elseif ($isBadVolt) {
+
+ kirimWA(
+ $phoneFix,
+
+ "⚡ *Pemberitahuan Perangkat Internet*\n\n".
+
+ "Yth. {$nama},\n\n".
+
+ "Sistem monitoring mendeteksi tegangan perangkat ONU berada di luar standar operasional.\n\n".
+
+ "🔌 Tegangan ONU : ".number_format($volt,2)." V\n\n".
+
+ "Kondisi ini dapat menyebabkan perangkat restart sendiri, koneksi tidak stabil, atau gangguan layanan internet.\n\n".
+
+ "Tim teknis kami telah menerima laporan otomatis dan akan melakukan pengecekan lebih lanjut.\n\n".
+
+ "Terima kasih.\n".
+ "RockNet NOC"
+ );
+
+ kirimWA(
+ $groupTeknisi,
+
+ "⚡ *ANOMALI VOLTAGE ONU*\n\n".
+
+ "👤 Pelanggan : {$nama}\n".
+ "🔢 SN ONU : {$sn}\n\n".
+
+ "🔌 Voltage : ".number_format($volt,2)." V\n\n".
+
+ "📋 Analisa :\n".
+ "{$voltKeterangan}\n\n".
+
+ "📍 Lokasi :\n{$maps}\n\n".
+
+ "🔧 Perlu pengecekan adaptor, kabel power, dan sumber listrik pelanggan."
+ );
+
+}
+
+
+ // ======================
+ // 🔥 UPDATE LOG ANTI SPAM
+ // ======================
+ $update = $conn->prepare("
+ INSERT INTO notif_device_log (sn, last_rx, last_voltage, last_sent)
+ VALUES (?, ?, ?, NOW())
+ ON DUPLICATE KEY UPDATE
+ last_rx = VALUES(last_rx),
+ last_voltage = VALUES(last_voltage),
+ last_sent = NOW()
+ ");
+
+ $update->execute([$sn, $rx, $volt]);
+
+ if (!$isChanged) {
+ echo "⏭ SKIP $sn | Tidak ada perubahan
";
+ continue;
+}
+
+ echo "✅ SENT $sn | RX:$rx | V:$volt
";
+}
\ No newline at end of file
diff --git a/api/auto_notif_odp.php b/api/auto_notif_odp.php
new file mode 100644
index 0000000..50047b8
--- /dev/null
+++ b/api/auto_notif_odp.php
@@ -0,0 +1,189 @@
+getConnection();
+
+if (!function_exists('kirimWA')) {
+function kirimWA($pesan) {
+ $token = "XjC9oSr4jECWG93JQRWf";
+
+ $data = [
+ "target" => "120363407747513164@g.us",
+ "message" => $pesan,
+ ];
+
+ $curl = curl_init();
+
+ curl_setopt_array($curl, [
+ CURLOPT_URL => "https://api.fonnte.com/send",
+ CURLOPT_RETURNTRANSFER => true,
+ CURLOPT_POST => true,
+ CURLOPT_POSTFIELDS => http_build_query($data),
+ CURLOPT_HTTPHEADER => [
+ "Authorization: $token"
+ ],
+ ]);
+
+ curl_exec($curl);
+ curl_close($curl);
+}
+}
+
+// ✅ Ambil semua ODP (KHUSUS USER 22)
+$stmt = $conn->query("
+ SELECT i.id, i.name, i.latitude, i.longitude
+ FROM ftth_items i
+ LEFT JOIN item_types it ON i.item_type_id = it.id
+ WHERE LOWER(it.name) = 'odp'
+ AND i.user_id = 22
+");
+
+$odps = $stmt->fetchAll(PDO::FETCH_ASSOC);
+
+foreach ($odps as $odp) {
+
+ // 🔥 ambil status terakhir
+ $cek = $conn->prepare("
+ SELECT last_status FROM notif_log
+ WHERE odp_id = ?
+ ");
+ $cek->execute([$odp['id']]);
+
+ $last = $cek->fetch(PDO::FETCH_ASSOC);
+ $lastStatus = $last['last_status'] ?? null;
+
+ // 🔥 ambil client
+ $stmtClient = $conn->prepare("
+ SELECT fi.id, fi.name, fi.serial_number
+ FROM cable_routes cr
+ JOIN ftth_items fi
+ ON (cr.to_item_id = fi.id OR cr.from_item_id = fi.id)
+ WHERE (cr.from_item_id = :id OR cr.to_item_id = :id)
+ AND fi.id != :id
+ ");
+ $stmtClient->bindParam(':id', $odp['id']);
+ $stmtClient->execute();
+
+ $clients = $stmtClient->fetchAll(PDO::FETCH_ASSOC);
+
+ $rxValues = [];
+ $clientBad = [];
+
+ foreach ($clients as $c) {
+
+ if (empty($c['serial_number'])) continue;
+
+ $query = json_encode(["_id" => $c['serial_number']]);
+ $url = "http://rmtstb.megadataisp.net:7557/devices/?query=" . urlencode($query);
+
+ $res = @file_get_contents($url);
+ if (!$res) continue;
+
+ $json = json_decode($res, true);
+
+ if (
+ isset($json[0]['VirtualParameters']['RXPower']['_value']) &&
+ is_numeric($json[0]['VirtualParameters']['RXPower']['_value'])
+ ) {
+ $rx = floatval($json[0]['VirtualParameters']['RXPower']['_value']);
+
+ $rxValues[] = $rx;
+
+ if ($rx < -23) {
+ $clientBad[] = $c['name'] . " (" . $rx . " dBm)";
+ }
+ }
+ }
+
+ // 🔴 skip kalau tidak ada data
+ if (count($rxValues) == 0) continue;
+
+ // 🔥 HITUNG (SAMA PERSIS KAYAK MANUAL)
+ $total = count($rxValues);
+ $bad = count($clientBad);
+ $good = $total - $bad;
+
+ $avg = round(array_sum($rxValues) / $total, 2);
+ $min = min($rxValues);
+
+ // 🔥 STATUS (SAMA PERSIS)
+ $selisih = abs($avg - $min);
+
+$status = "BAIK";
+
+if ($selisih > 1.5) {
+ $status = "WARNING";
+}
+
+if ($avg < -23 || $bad > ($total * 0.3)) {
+ $status = "WARNING";
+}
+
+if ($avg < -25 || $bad > ($total * 0.5)) {
+ $status = "BURUK";
+}
+
+if ($min < -27) {
+ $status = "KRITIS";
+}
+
+ // ❌ ANTI SPAM (kalau status sama, skip)
+ if ($status == $lastStatus) continue;
+
+ // 🔥 FORMAT WA (PERSIS KAYAK MANUAL)
+ $maps = "https://www.google.com/maps?q={$odp['latitude']},{$odp['longitude']}";
+
+ // ==============================
+ // 🚨 KIRIM SAAT BERMASALAH
+ // ==============================
+ if ($status != "BAIK") {
+
+ $pesan = "🚨 *AUTO LAPORAN ODP*\n\n";
+ $pesan .= "📍 *ODP:* {$odp['name']}\n";
+ $pesan .= "📊 *Status:* {$status}\n\n";
+
+ $pesan .= "👥 *Total Client:* {$total}\n";
+ $pesan .= "🟢 Client Baik: {$good}\n";
+ $pesan .= "🔴 Client Buruk: {$bad}\n\n";
+
+ $pesan .= "📶 *AVG RX:* {$avg} dBm\n";
+ $pesan .= "📉 *MIN RX:* {$min} dBm\n\n";
+
+ if (!empty($clientBad)) {
+ $pesan .= "⚠ *Client Bermasalah:*\n";
+ $pesan .= implode("\n", array_slice($clientBad, 0, 10));
+ $pesan .= "\n\n";
+ }
+
+ $pesan .= "📌 Lokasi:\n$maps\n\n";
+ $pesan .= "🔎 Silakan cek detail di dashboard.";
+
+ kirimWA($pesan);
+ }
+
+ // ==============================
+ // ✅ OPSIONAL: KIRIM SAAT NORMAL
+ // ==============================
+ elseif ($status == "BAIK" && $lastStatus != "BAIK") {
+
+ $pesan = "✅ *ODP SUDAH NORMAL*\n\n";
+ $pesan .= "📍 ODP: {$odp['name']}\n";
+ $pesan .= "Status sekarang: BAIK\n";
+ $pesan .= "AVG RX: {$avg} dBm\n";
+ $pesan .= "MIN RX: {$min} dBm\n\n";
+ $pesan .= "Jaringan sudah stabil 👍";
+
+ kirimWA($pesan);
+ }
+
+ // 🔥 UPDATE STATUS TERAKHIR
+ $update = $conn->prepare("
+ INSERT INTO notif_log (odp_id, last_status, last_sent)
+ VALUES (?, ?, NOW())
+ ON DUPLICATE KEY UPDATE
+ last_status = VALUES(last_status),
+ last_sent = NOW()
+ ");
+ $update->execute([$odp['id'], $status]);
+}
\ No newline at end of file
diff --git a/api/auto_notif_onu-bc.txt b/api/auto_notif_onu-bc.txt
new file mode 100644
index 0000000..68249cc
--- /dev/null
+++ b/api/auto_notif_onu-bc.txt
@@ -0,0 +1,144 @@
+getConnection();
+
+if (!function_exists('kirimWA')) {
+ function kirimWA($target, $pesan) {
+ $token = "XjC9oSr4jECWG93JQRWf";
+
+ $data = [
+ "target" => $target,
+ "message" => $pesan,
+ ];
+
+ $curl = curl_init();
+
+ curl_setopt_array($curl, [
+ CURLOPT_URL => "https://api.fonnte.com/send",
+ CURLOPT_RETURNTRANSFER => true,
+ CURLOPT_POST => true,
+ CURLOPT_POSTFIELDS => http_build_query($data),
+ CURLOPT_HTTPHEADER => [
+ "Authorization: $token"
+ ],
+ ]);
+
+ curl_exec($curl);
+ curl_close($curl);
+ }
+}
+// 🔥 ID GROUP TEKNISI
+$groupTeknisi = "120363427232707228@g.us";
+
+// ambil semua ONU yang punya nomor HP + lokasi pelanggan
+$stmt = $conn->query("
+ SELECT
+ o.sn,
+ o.status,
+ f.name,
+ f.customer_phone,
+ f.latitude,
+ f.longitude
+ FROM onu_status o
+ JOIN ftth_items f ON f.sn_onu = o.sn
+ JOIN item_types it ON f.item_type_id = it.id
+ WHERE f.customer_phone IS NOT NULL
+ AND LOWER(it.name) = 'pelanggan'
+");
+
+$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
+
+foreach ($data as $row) {
+
+ $sn = $row['sn'];
+ $status = $row['status'];
+ $nama = $row['name'];
+ $phone = $row['customer_phone'];
+ $lat = $row['latitude'];
+ $lng = $row['longitude'];
+
+ // 🔥 buat link maps
+ $maps = ($lat && $lng)
+ ? "https://www.google.com/maps?q={$lat},{$lng}"
+ : "-";
+
+ // 🔥 cek status terakhir
+ $cek = $conn->prepare("
+ SELECT last_status FROM notif_onu_log WHERE sn = ?
+ ");
+ $cek->execute([$sn]);
+
+ $last = $cek->fetch(PDO::FETCH_ASSOC);
+ $lastStatus = $last['last_status'] ?? null;
+
+ // ❌ anti spam
+ if ($status == $lastStatus) continue;
+
+ // ======================
+ // 🔥 FORMAT PESAN
+ // ======================
+
+ $pesan = "";
+
+ if ($status == "LASER OUT") {
+ $pesan .= "🚨 *GANGGUAN INTERNET*\n\n";
+ $pesan .= "Pelanggan: {$nama}\n\n";
+ $pesan .= "Terjadi gangguan pada kabel fiber (FO CUT).\n";
+ $pesan .= "kami akan informasikan kepada tim teknis untuk segera ke lokasi kakak.\n\n";
+ $pesan .= "estimasi perbaikan 4 Jam pengerjaan.\n\n";
+ $pesan .= "Mohon ditunggu 🙏";
+
+ // ======================
+ // 🔥 NOTIF KE TEKNISI (KHUSUS LOS)
+ // ======================
+ $pesanTeknisi = "🚨 *FO CUT TERDETEKSI*\n\n";
+ $pesanTeknisi .= "👤 Pelanggan: {$nama}\n";
+ $pesanTeknisi .= "📡 SN: {$sn}\n\n";
+ $pesanTeknisi .= "Status: LOS\n";
+ $pesanTeknisi .= "Estimasi: 4 Jam\n\n";
+ $pesanTeknisi .= "📍 Lokasi:\n{$maps}\n\n";
+ $pesanTeknisi .= "⚠ Segera ke lokasi";
+
+ // kirim ke group teknisi
+ kirimWA($groupTeknisi, $pesanTeknisi);
+ }
+
+ elseif ($status == "POWER FAIL") {
+ $pesan .= "⚡ *PERANGKAT MATI*\n\n";
+ $pesan .= "Pelanggan: {$nama}\n\n";
+ $pesan .= "Perangkat ONU terdeteksi mati / tidak mendapat listrik.\n";
+ $pesan .= "Silakan cek adaptor atau listrik di lokasi.\n\n";
+ $pesan .= "Jika terjadi kendala dilokasi mohon konfirmasinya kakak\n\n";
+ $pesan .= "bisa di bantu videokan alat atau foto alat dilokasi kakak🙏\n\n";
+ $pesan .= "Terima kasih 🙏";
+ }
+
+ elseif ($status == "ONLINE" && $lastStatus != "ONLINE") {
+ $pesan .= "✅ *INTERNET NORMAL*\n\n";
+ $pesan .= "Pelanggan: {$nama}\n\n";
+ $pesan .= "Koneksi internet sudah kembali normal.\n\n";
+ $pesan .= "Internet saat ini bisa dicoba kembali\n\n";
+ $pesan .= "Terima kasih 🙏";
+ }
+
+ // kirim kalau ada pesan
+ if ($pesan != "") {
+
+ // 🔥 kirim WA ke pelanggan (TIDAK DIUBAH)
+ kirimWA($phone, $pesan);
+
+ // update log
+ $update = $conn->prepare("
+ INSERT INTO notif_onu_log (sn, last_status, last_sent)
+ VALUES (?, ?, NOW())
+ ON DUPLICATE KEY UPDATE
+ last_status = VALUES(last_status),
+ last_sent = NOW()
+ ");
+ $update->execute([$sn, $status]);
+
+ echo "Kirim ke $phone | $status
";
+ }
+}
diff --git a/api/auto_notif_onu.php b/api/auto_notif_onu.php
new file mode 100644
index 0000000..3ac6d76
--- /dev/null
+++ b/api/auto_notif_onu.php
@@ -0,0 +1,161 @@
+getConnection();
+
+if (!function_exists('kirimWA')) {
+ function kirimWA($target, $pesan) {
+ $token = "XjC9oSr4jECWG93JQRWf";
+
+ $data = [
+ "target" => $target,
+ "message" => $pesan,
+ ];
+
+ $curl = curl_init();
+
+ curl_setopt_array($curl, [
+ CURLOPT_URL => "https://api.fonnte.com/send",
+ CURLOPT_RETURNTRANSFER => true,
+ CURLOPT_POST => true,
+ CURLOPT_POSTFIELDS => http_build_query($data),
+ CURLOPT_HTTPHEADER => [
+ "Authorization: $token"
+ ],
+ ]);
+
+ curl_exec($curl);
+ curl_close($curl);
+ }
+}
+// 🔥 ID GROUP TEKNISI
+$groupTeknisi = "120363427232707228@g.us";
+
+// ambil semua ONU yang punya nomor HP + lokasi pelanggan
+$stmt = $conn->query("
+ SELECT
+ o.sn,
+ o.status,
+ f.name,
+ f.customer_phone,
+ f.latitude,
+ f.longitude
+ FROM onu_status o
+ JOIN ftth_items f ON f.sn_onu = o.sn
+ JOIN item_types it ON f.item_type_id = it.id
+ WHERE f.customer_phone IS NOT NULL
+ AND LOWER(it.name) = 'pelanggan'
+");
+
+$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
+
+foreach ($data as $row) {
+
+ $sn = $row['sn'];
+ $status = $row['status'];
+ $nama = $row['name'];
+ $phone = $row['customer_phone'];
+ $lat = $row['latitude'];
+ $lng = $row['longitude'];
+
+ // 🔥 buat link maps
+ $maps = ($lat && $lng)
+ ? "https://www.google.com/maps?q={$lat},{$lng}"
+ : "-";
+
+ // 🔥 cek status terakhir
+ $cek = $conn->prepare("
+ SELECT last_status FROM notif_onu_log WHERE sn = ?
+ ");
+ $cek->execute([$sn]);
+
+ $last = $cek->fetch(PDO::FETCH_ASSOC);
+ $lastStatus = $last['last_status'] ?? null;
+
+ // ❌ anti spam
+ if ($status == $lastStatus) continue;
+
+ // ======================
+ // 🔥 FORMAT PESAN
+ // ======================
+
+ $pesan = "";
+
+ if ($status == "LASER OUT") {
+ $pesan .= "🚨 *GANGGUAN INTERNET*\n\n";
+ $pesan .= "Pelanggan: {$nama}\n\n";
+ $pesan .= "Terjadi gangguan pada kabel fiber (FO CUT).\n";
+ $pesan .= "kami akan informasikan kepada tim teknis untuk segera ke lokasi kakak.\n\n";
+ $pesan .= "estimasi perbaikan 4 Jam pengerjaan.\n\n";
+ $pesan .= "Mohon ditunggu 🙏";
+
+ // ======================
+ // 🔥 NOTIF KE TEKNISI (KHUSUS LOS)
+ // ======================
+ $pesanTeknisi = "🚨 *FO CUT TERDETEKSI*\n\n";
+ $pesanTeknisi .= "👤 Pelanggan: {$nama}\n";
+ $pesanTeknisi .= "📡 SN: {$sn}\n\n";
+ $pesanTeknisi .= "Status: LOS\n";
+ $pesanTeknisi .= "Estimasi: 4 Jam\n\n";
+ $pesanTeknisi .= "📍 Lokasi:\n{$maps}\n\n";
+ $pesanTeknisi .= "⚠ Segera ke lokasi";
+
+ // kirim ke group teknisi
+ kirimWA($groupTeknisi, $pesanTeknisi);
+ }
+
+ elseif ($status == "POWER FAIL") {
+
+ // 🔥 NOTIF KE PELANGGAN
+ $pesan .= "⚡ *PERANGKAT MATI*\n\n";
+ $pesan .= "Pelanggan: {$nama}\n\n";
+ $pesan .= "Perangkat ONU terdeteksi mati / tidak mendapat listrik.\n";
+ $pesan .= "Silakan cek adaptor atau listrik di lokasi.\n\n";
+ $pesan .= "Jika terjadi kendala dilokasi mohon konfirmasinya kakak\n\n";
+ $pesan .= "Bisa dibantu videokan atau foto kondisi alat 🙏\n\n";
+ $pesan .= "Terima kasih 🙏";
+
+ // ======================
+ // 🔥 NOTIF KE TEKNISI (POWER FAIL)
+ // ======================
+ $pesanTeknisi = "⚡ *POWER FAIL TERDETEKSI*\n\n";
+ $pesanTeknisi .= "👤 Pelanggan: {$nama}\n";
+ $pesanTeknisi .= "📡 SN: {$sn}\n\n";
+ $pesanTeknisi .= "Status: POWER FAIL\n\n";
+ $pesanTeknisi .= "📍 Lokasi:\n{$maps}\n\n";
+ $pesanTeknisi .= "ℹ Saat ini sedang konfirmasi ke pelanggan terkait kondisi alat di lokasi.\n";
+ $pesanTeknisi .= "📸 Jika sudah ada info, akan dikirim foto / video alat di grup ini.\n\n";
+ $pesanTeknisi .= "Mohon standby 🙏";
+
+ // kirim ke group teknisi
+ kirimWA($groupTeknisi, $pesanTeknisi);
+}
+
+ elseif ($status == "ONLINE" && $lastStatus != "ONLINE") {
+ $pesan .= "✅ *INTERNET NORMAL*\n\n";
+ $pesan .= "Pelanggan: {$nama}\n\n";
+ $pesan .= "Koneksi internet sudah kembali normal.\n\n";
+ $pesan .= "Internet saat ini bisa dicoba kembali\n\n";
+ $pesan .= "Terima kasih 🙏";
+ }
+
+ // kirim kalau ada pesan
+ if ($pesan != "") {
+
+ // 🔥 kirim WA ke pelanggan (TIDAK DIUBAH)
+ kirimWA($phone, $pesan);
+
+ // update log
+ $update = $conn->prepare("
+ INSERT INTO notif_onu_log (sn, last_status, last_sent)
+ VALUES (?, ?, NOW())
+ ON DUPLICATE KEY UPDATE
+ last_status = VALUES(last_status),
+ last_sent = NOW()
+ ");
+ $update->execute([$sn, $status]);
+
+ echo "Kirim ke $phone | $status
";
+ }
+}
diff --git a/api/auto_runner.php b/api/auto_runner.php
new file mode 100644
index 0000000..70b33e1
--- /dev/null
+++ b/api/auto_runner.php
@@ -0,0 +1,55 @@
+= $interval_odp) {
+ echo "📡 Cek ODP: " . date("H:i:s") . PHP_EOL;
+
+ include __DIR__ . "/auto_notif_odp.php";
+
+ $last_odp = $now;
+ }
+
+ // ===============================
+ // 🔥 CEK ONU + NOTIF (1 menit)
+ // ===============================
+ if (($now - $last_onu) >= $interval_onu) {
+ echo "📶 Cek ONU: " . date("H:i:s") . PHP_EOL;
+
+
+ include __DIR__ . "/auto_notif_onu.php"; // kirim notif WA
+
+ $last_onu = $now;
+ }
+
+ // ===============================
+ // 🔥 CEK OLT (3 menit)
+ // ===============================
+ //if (($now - $last_olt) >= $interval_olt) {
+ // echo "🛰️ Cek OLT: " . date("H:i:s") . PHP_EOL;
+
+ // include __DIR__ . "/ambil_dataOLT.php"; // update status ONU
+
+// $last_olt = $now;
+ // }
+
+ // ⏳ delay kecil biar CPU gak 100%
+ sleep(5);
+}
\ No newline at end of file
diff --git a/api/backup.txt b/api/backup.txt
new file mode 100644
index 0000000..6291ec9
--- /dev/null
+++ b/api/backup.txt
@@ -0,0 +1,51 @@
+= 60) {
+ echo "Cek ODP: " . date("H:i:s") . PHP_EOL;
+ require_once __DIR__ . "/auto_notif_odp.php";
+ $lastODP = $now;
+ }
+
+ // ======================
+ // CEK ONU (tiap 60 detik)
+ // ======================
+ if ($now - $lastONU >= 60) {
+ echo "Cek ONU: " . date("H:i:s") . PHP_EOL;
+ require_once __DIR__ . "/auto_notif_onu.php";
+ $lastONU = $now;
+ }
+
+ // ==========================
+ // AMBIL DATA OLT (tiap 5 menit)
+ // ==========================
+ if ($now - $lastOLT >= 300) {
+ echo "Ambil Data OLT: " . date("H:i:s") . PHP_EOL;
+ require_once __DIR__ . "/ambil_dataOLT.php";
+ $lastOLT = $now;
+ }
+
+ // jeda kecil biar CPU nggak full
+ sleep(5);
+}
+
+
+rmtstb.megadataisp.net
+
+
+📡 Cek ODP: 20:16:25
+📶 Cek ONU: 20:16:33
+Kirim ke 6282338451677 | ONLINE
Kirim ke 6281252188305 | ONLINE
📡 Cek ODP: 20:17:29
\ No newline at end of file
diff --git a/api/bc-ambildata_olt.txt b/api/bc-ambildata_olt.txt
new file mode 100644
index 0000000..4603818
--- /dev/null
+++ b/api/bc-ambildata_olt.txt
@@ -0,0 +1,119 @@
+getConnection();
+
+// ================= CONFIG =================
+$login_url = "http://10.255.254.21/login";
+$data_url = "http://10.255.254.21/ontinfo_table";
+
+$username = "root";
+$password = "@lokal234";
+
+$cookie = __DIR__ . "/cookie.txt";
+
+// ================= LOGIN =================
+$ch = curl_init();
+curl_setopt($ch, CURLOPT_URL, $login_url);
+curl_setopt($ch, CURLOPT_POST, true);
+curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
+ "username" => $username,
+ "password" => $password
+]));
+curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie);
+curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie);
+curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
+
+curl_exec($ch);
+curl_close($ch);
+
+// ================= AMBIL DATA (JSON) =================
+$ch = curl_init();
+curl_setopt($ch, CURLOPT_URL, $data_url);
+curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie);
+curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
+
+$response = curl_exec($ch);
+
+if ($response === false) {
+ die("CURL ERROR: " . curl_error($ch));
+}
+
+curl_close($ch);
+
+// simpan debug
+file_put_contents("debug_onu.json", $response);
+
+// ================= PARSING JSON =================
+$data = json_decode($response, true);
+
+if (!isset($data['data']) || empty($data['data'])) {
+ die("DATA KOSONG / LOGIN GAGAL / ENDPOINT SALAH");
+}
+
+foreach ($data['data'] as $onu) {
+
+ $sn = $onu['ont_sn'] ?? '';
+ $rx = $onu['receive_power'] ?? 0;
+ $state = $onu['state'] ?? 0;
+ $cause = $onu['last_d_cause'] ?? '';
+
+ // skip kalau SN kosong
+ if (empty($sn)) {
+ continue;
+ }
+
+ // ================= STATUS =================
+ $cause = strtolower($cause);
+
+// 🔥 PRIORITAS 1: dari cause
+if (strpos($cause, 'laser out') !== false || strpos($cause, 'fiber') !== false) {
+ $status = "LASER OUT";
+}
+elseif (strpos($cause, 'power down') !== false || strpos($cause, 'dying-gasp') !== false) {
+ $status = "POWER FAIL";
+}
+
+// 🔥 PRIORITAS 2: fallback dari state + RX
+else {
+ if ($state == 0 && $rx <= -30) {
+ $status = "LASER OUT"; // default ke LOS kalau tidak jelas
+ } elseif ($rx <= -30) {
+ $status = "POWER FAIL";
+ } else {
+ $status = "ONLINE";
+ }
+}
+
+ // ================= SIMPAN DB =================
+ $conn->query("
+ INSERT INTO onu_status (sn, status, rx_power, last_update)
+ VALUES ('$sn', '$status', '$rx', NOW())
+ ON DUPLICATE KEY UPDATE
+ last_status = status,
+ status = '$status',
+ rx_power = '$rx',
+ last_update = NOW()
+ ");
+
+ $conn->query("
+ INSERT INTO status_onu_histori (sn, status, rx_power, cause, created_at)
+ VALUES (
+ '$sn',
+ '$status',
+ '$rx',
+ '$cause',
+ NOW()
+ )
+");
+
+ echo "SN: $sn | STATUS: $status | RX: $rx
";
+}
+
+echo "
DONE ✅";
+?>
\ No newline at end of file
diff --git a/api/bc-notif-redaman dan volt.txt b/api/bc-notif-redaman dan volt.txt
new file mode 100644
index 0000000..1ff7cbd
--- /dev/null
+++ b/api/bc-notif-redaman dan volt.txt
@@ -0,0 +1,224 @@
+getConnection();
+
+// 🔥 GROUP TEKNISI
+$groupTeknisi = "120363427232707228@g.us";
+
+// ======================
+// 🔥 FUNCTION WA
+// ======================
+if (!function_exists('kirimWA')) {
+function kirimWA($target, $pesan) {
+ if (!$target) return;
+
+ $token = "XjC9oSr4jECWG93JQRWf";
+
+ $data = [
+ "target" => $target,
+ "message" => $pesan,
+ ];
+
+ $curl = curl_init();
+
+ curl_setopt_array($curl, [
+ CURLOPT_URL => "https://api.fonnte.com/send",
+ CURLOPT_RETURNTRANSFER => true,
+ CURLOPT_POST => true,
+ CURLOPT_POSTFIELDS => http_build_query($data),
+ CURLOPT_HTTPHEADER => [
+ "Authorization: $token"
+ ],
+ CURLOPT_TIMEOUT => 10
+ ]);
+
+ curl_exec($curl);
+ curl_close($curl);
+}
+}
+
+// ======================
+// 🔥 TEST MODE (OPSIONAL)
+// ======================
+$TEST_MODE = false;
+
+// ======================
+// 🔥 AMBIL DATA DARI DATABASE (JOIN HISTORY)
+// ======================
+$stmt = $conn->query("
+ SELECT
+ f.id,
+ f.name,
+ f.sn_onu,
+ f.latitude,
+ f.longitude,
+ f.customer_phone,
+
+ o.rx_power,
+ o.voltage,
+ o.updated_at
+
+ FROM ftth_items f
+
+ LEFT JOIN onu_daily_history o
+ ON o.sn = f.sn_onu
+
+ INNER JOIN item_types it
+ ON it.id = f.item_type_id
+
+ WHERE f.sn_onu IS NOT NULL
+ AND LOWER(it.name) = 'pelanggan'
+");
+
+$dataItems = $stmt->fetchAll(PDO::FETCH_ASSOC);
+
+foreach ($dataItems as $item) {
+
+ usleep(200000);
+
+ $sn = strtoupper(trim($item['sn_onu']));
+ $nama = $item['name'];
+ $lat = $item['latitude'];
+ $lng = $item['longitude'];
+ $phone = $item['customer_phone'];
+
+ // ======================
+ // 🔥 AMBIL RX & VOLT DARI DB
+ // ======================
+ $rx = isset($item['rx_power']) ? floatval($item['rx_power']) : null;
+ $volt = isset($item['voltage']) ? floatval($item['voltage']) : null;
+
+ if ($rx === null && $volt === null) {
+ continue;
+ }
+
+ // ======================
+ // 🔥 STATUS DETEKSI
+ // ======================
+ $isBadRx = ($rx !== null && $rx <= -25.99);
+ $isBadVolt = ($volt !== null && $volt < 3.29);
+
+ echo "DEBUG $sn | RX:$rx | Volt:$volt
";
+
+ if (!$isBadRx && !$isBadVolt) {
+ continue;
+ }
+
+ // ======================
+ // 🔥 CEK ANTI SPAM LOG
+ // ======================
+ $cek = $conn->prepare("
+ SELECT last_rx, last_voltage
+ FROM notif_device_log
+ WHERE sn = ?
+ ");
+ $cek->execute([$sn]);
+ $last = $cek->fetch(PDO::FETCH_ASSOC);
+
+ $lastRx = $last['last_rx'] ?? null;
+ $lastVolt = $last['last_voltage'] ?? null;
+
+ $isChanged = ($lastRx != $rx || $lastVolt != $volt);
+
+ if (!$isChanged) {
+ continue;
+ }
+
+ // ======================
+ // 🔥 MAPS
+ // ======================
+ $maps = ($lat && $lng)
+ ? "https://www.google.com/maps?q={$lat},{$lng}"
+ : "-";
+
+ // ======================
+ // 🔥 FORMAT NOMOR
+ // ======================
+ $phoneFix = null;
+ if ($phone) {
+ $phoneFix = preg_replace('/[^0-9]/', '', $phone);
+ if (substr($phoneFix, 0, 1) == '0') {
+ $phoneFix = '62' . substr($phoneFix, 1);
+ }
+ }
+
+ // ======================
+ // 🔥 NOTIFIKASI
+ // ======================
+
+ if ($isBadRx && $isBadVolt) {
+
+ kirimWA($phoneFix,
+ "🚨 *Gangguan Jaringan & Perangkat*\n\n" .
+ "Yth. {$nama},\n" .
+ "📉 RX: " . number_format($rx,2) . " dBm\n" .
+ "🔌 Volt: " . number_format($volt,2) . " V\n\n" .
+ "Gangguan pada jaringan & perangkat terdeteksi.\n" .
+ "Estimasi perbaikan ±2 jam.\n\n" .
+ "Mohon maaf 🙏"
+ );
+
+ kirimWA($groupTeknisi,
+ "🚨 *DOUBLE ISSUE*\n\n" .
+ "👤 {$nama}\n" .
+ "📉 RX: {$rx} dBm\n" .
+ "🔌 Volt: " . number_format($volt,2) . " V\n\n" .
+ "📡 Gangguan IKR + ONU\n" .
+ "📍 {$maps}\n\n" .
+ "⚠ PRIORITAS TINGGI"
+ );
+
+ } elseif ($isBadRx) {
+
+ kirimWA($phoneFix,
+ "🚨 *Gangguan Jaringan*\n\n" .
+ "Yth. {$nama},\n" .
+ "📉 RX: {$rx} dBm\n\n" .
+ "Terjadi gangguan pada jalur fiber.\n" .
+ "Tim akan segera ke lokasi.\n"
+ );
+
+ kirimWA($groupTeknisi,
+ "🚨 *REDAMAN TIDAK NORMAL*\n\n" .
+ "👤 {$nama}\n" .
+ "📉 RX: {$rx} dBm\n" .
+ "📍 {$maps}"
+ );
+
+ } elseif ($isBadVolt) {
+
+ kirimWA($phoneFix,
+ "⚡ *Perangkat Bermasalah*\n\n" .
+ "Yth. {$nama},\n" .
+ "🔌 Volt: " . number_format($volt,2) . " V\n\n" .
+ "Indikasi power tidak stabil.\n"
+ );
+
+ kirimWA($groupTeknisi,
+ "⚡ *VOLTAGE TIDAK NORMAL*\n\n" .
+ "👤 {$nama}\n" .
+ "🔌 Volt: " . number_format($volt,2) . " V\n" .
+ "📍 {$maps}"
+ );
+ }
+
+ // ======================
+ // 🔥 UPDATE LOG ANTI SPAM
+ // ======================
+ $update = $conn->prepare("
+ INSERT INTO notif_device_log (sn, last_rx, last_voltage, last_sent)
+ VALUES (?, ?, ?, NOW())
+ ON DUPLICATE KEY UPDATE
+ last_rx = VALUES(last_rx),
+ last_voltage = VALUES(last_voltage),
+ last_sent = NOW()
+ ");
+
+ $update->execute([$sn, $rx, $volt]);
+
+ echo "✅ SENT $sn | RX:$rx | V:$volt
";
+}
\ No newline at end of file
diff --git a/api/cookie.txt b/api/cookie.txt
new file mode 100644
index 0000000..c31d989
--- /dev/null
+++ b/api/cookie.txt
@@ -0,0 +1,4 @@
+# Netscape HTTP Cookie File
+# https://curl.se/docs/http-cookies.html
+# This file was generated by libcurl! Edit at your own risk.
+
diff --git a/api/data_log_hsgq.php b/api/data_log_hsgq.php
new file mode 100644
index 0000000..ecd5fce
--- /dev/null
+++ b/api/data_log_hsgq.php
@@ -0,0 +1,87 @@
+ $username,
+ "password" => $password
+]));
+curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie);
+curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie);
+curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
+
+$result = curl_exec($ch);
+
+if (curl_errno($ch)) {
+ die("LOGIN ERROR : " . curl_error($ch));
+}
+
+curl_close($ch);
+
+// ================= AMBIL DATA =================
+$ch = curl_init();
+
+curl_setopt($ch, CURLOPT_URL, $data_url);
+curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie);
+curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
+
+$response = curl_exec($ch);
+
+if (curl_errno($ch)) {
+ die("DATA ERROR : " . curl_error($ch));
+}
+
+curl_close($ch);
+
+// simpan raw response
+file_put_contents("debug_hsgq.json", $response);
+
+// ================= TAMPILKAN =================
+$data = json_decode($response, true);
+
+echo "
"; + echo htmlspecialchars(substr($response, 0, 5000)); + echo ""; + exit; +} + +echo "
";
+
+if (isset($data['data'][0])) {
+
+ echo "=== DATA ONU PERTAMA ===\n\n";
+
+ print_r($data['data'][0]);
+
+ echo "\n\n=== NAMA FIELD ===\n\n";
+
+ foreach ($data['data'][0] as $key => $value) {
+ echo $key . "\n";
+ }
+
+} else {
+
+ print_r($data);
+
+}
+
+echo "";
\ No newline at end of file
diff --git a/api/debug_hsgq.json b/api/debug_hsgq.json
new file mode 100644
index 0000000..10af2fe
--- /dev/null
+++ b/api/debug_hsgq.json
@@ -0,0 +1 @@
+Not found
diff --git a/api/debug_onu.html b/api/debug_onu.html
new file mode 100644
index 0000000..913a243
--- /dev/null
+++ b/api/debug_onu.html
@@ -0,0 +1,1176 @@
+{
+ "code":1,
+ "message":"success",
+ "data":[
+ {
+ "identifier":256,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"ARTINI",
+ "ont_sn":"VSOL00addd35",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-24.6860",
+ "last_u_time":"2026\/03\/29 14:09:13",
+ "last_d_time":"2026\/03\/29 14:08:02",
+ "last_d_cause":"",
+ "ont_description":"ARTINI",
+ "parent":0
+ },
+ {
+ "identifier":257,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"SATRIA PERUM PANGGUNG",
+ "ont_sn":"VSOL00ad1105",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-26.0220",
+ "last_u_time":"2026\/03\/27 21:25:29",
+ "last_d_time":"2026\/03\/27 21:24:30",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":258,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"RIDA AGUS",
+ "ont_sn":"HWTCa90adda0",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-20.7060",
+ "last_u_time":"2026\/03\/28 10:13:31",
+ "last_d_time":"2026\/03\/28 10:08:49",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":259,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"SMP 6 SITUBONDO",
+ "ont_sn":"HWTCa90add88",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-21.2500",
+ "last_u_time":"2026\/03\/30 07:32:29",
+ "last_d_time":"2026\/03\/30 07:29:59",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":260,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"BASRIYADI",
+ "ont_sn":"HWTCa90aaf00",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-20.6060",
+ "last_u_time":"2026\/03\/08 01:31:34",
+ "last_d_time":"2026\/03\/07 18:41:39",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":261,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"IRWAN",
+ "ont_sn":"HWTCd1b3aa28",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-21.6120",
+ "last_u_time":"2026\/03\/28 10:12:39",
+ "last_d_time":"2026\/03\/28 10:08:49",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":262,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"TEGUH ADI",
+ "ont_sn":"HWTCa90a4760",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-20.5560",
+ "last_u_time":"2026\/03\/28 10:13:22",
+ "last_d_time":"2026\/03\/28 10:08:49",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":263,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"MALD\/H1\/1\/3\/13",
+ "ont_sn":"CDTCaf8e7bf1",
+ "state":1,
+ "rstate":2,
+ "cstate":0,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-30.0000",
+ "last_u_time":"2026\/03\/28 10:12:32",
+ "last_d_time":"2026\/03\/30 19:15:23",
+ "last_d_cause":"Power down",
+ "ont_description":"BAGOES FARIZNA ",
+ "parent":0
+ },
+ {
+ "identifier":264,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"FENTI",
+ "ont_sn":"HWTCa90aaed8",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-20.8620",
+ "last_u_time":"2026\/03\/28 10:13:38",
+ "last_d_time":"2026\/03\/28 10:08:49",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":265,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"DESY\/SUPARJO",
+ "ont_sn":"HWTCa90aabf8",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-21.6120",
+ "last_u_time":"2026\/03\/28 13:35:50",
+ "last_d_time":"2026\/03\/28 13:34:17",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":266,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"DIFTA DWI",
+ "ont_sn":"HWTCd1b32230",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-21.6120",
+ "last_u_time":"2026\/03\/28 10:36:49",
+ "last_d_time":"2026\/03\/28 07:45:40",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":267,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"AYANG",
+ "ont_sn":"HWTCa90addb0",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-20.0880",
+ "last_u_time":"2026\/03\/28 10:13:25",
+ "last_d_time":"2026\/03\/28 10:08:49",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":268,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"TIO",
+ "ont_sn":"HWTCd1b40e20",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-21.7400",
+ "last_u_time":"2026\/03\/30 06:17:48",
+ "last_d_time":"2026\/03\/30 06:14:35",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":269,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"ADIT",
+ "ont_sn":"HWTCd1b34100",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-21.6120",
+ "last_u_time":"2026\/03\/28 10:12:41",
+ "last_d_time":"2026\/03\/28 10:08:49",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":270,
+ "lineprof_id":2,
+ "srvprof_id":0,
+ "ont_name":"VEGA\/MAMANG",
+ "ont_sn":"ZXICaefca657",
+ "state":1,
+ "rstate":2,
+ "cstate":0,
+ "mstate":0,
+ "dev_type":"SFU",
+ "receive_power":"-30.0000",
+ "last_u_time":"2026\/03\/28 14:23:35",
+ "last_d_time":"2026\/03\/28 14:23:39",
+ "last_d_cause":"Laser out",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":271,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"AZKA",
+ "ont_sn":"HWTCa90a5b00",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-24.5600",
+ "last_u_time":"2026\/03\/28 10:13:31",
+ "last_d_time":"2026\/03\/28 10:08:49",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":272,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"DIMAS OLEAN",
+ "ont_sn":"HWTCd1b1bf80",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-21.0800",
+ "last_u_time":"2026\/03\/25 11:34:15",
+ "last_d_time":"2026\/03\/25 11:29:47",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":273,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"ASWA",
+ "ont_sn":"HWTCa90a9808",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-19.6280",
+ "last_u_time":"2026\/03\/28 10:13:22",
+ "last_d_time":"2026\/03\/28 10:08:50",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":274,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"ZAINUL",
+ "ont_sn":"HWTCd1b35cc8",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-21.4880",
+ "last_u_time":"2026\/03\/28 11:49:17",
+ "last_d_time":"2026\/03\/28 10:08:49",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":275,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"PAK JONO",
+ "ont_sn":"HWTCa90af408",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-19.8300",
+ "last_u_time":"2026\/03\/28 18:12:01",
+ "last_d_time":"2026\/03\/28 18:08:54",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":276,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"DAVID",
+ "ont_sn":"HWTCd1b35928",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-20.2240",
+ "last_u_time":"2026\/03\/28 10:12:55",
+ "last_d_time":"2026\/03\/28 10:08:49",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":277,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"DIKI",
+ "ont_sn":"HWTCd1b34b38",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-21.6760",
+ "last_u_time":"2026\/03\/29 04:18:57",
+ "last_d_time":"2026\/03\/29 04:16:42",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":278,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"AZKA TOKO",
+ "ont_sn":"HWTCa90b9ee0",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-20.6560",
+ "last_u_time":"2026\/03\/28 10:13:31",
+ "last_d_time":"2026\/03\/28 10:08:49",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":279,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"PAK GAGUK",
+ "ont_sn":"HWTCa90addb8",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-22.9260",
+ "last_u_time":"2026\/03\/29 09:50:05",
+ "last_d_time":"2026\/03\/29 09:48:35",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":280,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"IKE PUJI",
+ "ont_sn":"HWTCa90b1170",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-18.3580",
+ "last_u_time":"2026\/03\/30 18:44:56",
+ "last_d_time":"2026\/03\/30 18:34:28",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":281,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"VINGGO",
+ "ont_sn":"HWTCa90a47b0",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-23.3740",
+ "last_u_time":"2026\/03\/28 10:13:17",
+ "last_d_time":"2026\/03\/28 10:08:49",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":282,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"DEWI DKITE",
+ "ont_sn":"CDTCaf8e7c0c",
+ "state":1,
+ "rstate":2,
+ "cstate":0,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-30.0000",
+ "last_u_time":"2026\/03\/28 10:12:41",
+ "last_d_time":"2026\/03\/30 01:34:18",
+ "last_d_cause":"Power down",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":283,
+ "lineprof_id":2,
+ "srvprof_id":0,
+ "ont_name":"CCTV_TALAS",
+ "ont_sn":"HWTCa90a5520",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-22.1480",
+ "last_u_time":"2026\/03\/28 10:13:31",
+ "last_d_time":"2026\/03\/28 10:08:49",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":284,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"EKI",
+ "ont_sn":"HWTCa90a46b8",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-22.9260",
+ "last_u_time":"2026\/03\/29 14:49:31",
+ "last_d_time":"2026\/03\/27 23:19:38",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":285,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"ALEX",
+ "ont_sn":"HWTCa90b4c38",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-23.9800",
+ "last_u_time":"2026\/03\/28 17:32:44",
+ "last_d_time":"2026\/03\/28 17:31:09",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":286,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"TOLAK SAFARI",
+ "ont_sn":"CDTCaf8ee4ff",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-19.7480",
+ "last_u_time":"2026\/03\/30 19:19:04",
+ "last_d_time":"2026\/03\/30 19:18:23",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":287,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"CINDY",
+ "ont_sn":"HWTCa90ae460",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-20.4100",
+ "last_u_time":"2026\/03\/08 04:41:30",
+ "last_d_time":"2026\/03\/07 18:03:25",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":288,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"CHOIRUL ANWAR",
+ "ont_sn":"CDTCaf8e7bfa",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-15.7200",
+ "last_u_time":"2026\/03\/28 10:13:13",
+ "last_d_time":"2026\/03\/28 10:12:20",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":289,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"AFIF",
+ "ont_sn":"HWTCd1b37980",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-19.1380",
+ "last_u_time":"2026\/03\/18 19:36:55",
+ "last_d_time":"2026\/03\/18 19:29:59",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":290,
+ "lineprof_id":5,
+ "srvprof_id":0,
+ "ont_name":"AINI",
+ "ont_sn":"HWTCa90a5558",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-18.0700",
+ "last_u_time":"2026\/03\/27 23:37:15",
+ "last_d_time":"2026\/03\/27 23:37:11",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":291,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"EKA",
+ "ont_sn":"CDTCaf8e7c03",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-23.2800",
+ "last_u_time":"2026\/03\/28 10:12:32",
+ "last_d_time":"2026\/03\/28 10:08:49",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":292,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"PAK AGUS",
+ "ont_sn":"ZTEGcf5ac619",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"SFU",
+ "receive_power":"-21.6120",
+ "last_u_time":"2026\/03\/25 13:48:27",
+ "last_d_time":"2026\/03\/23 05:27:02",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":293,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"NURHIDAYAT",
+ "ont_sn":"CDTCaf8ee4ed",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-20.7060",
+ "last_u_time":"2026\/03\/27 10:08:18",
+ "last_d_time":"2026\/03\/27 10:02:11",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":294,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"PUTRI WULANSARI",
+ "ont_sn":"HWTCa90a5350",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-18.9280",
+ "last_u_time":"2026\/03\/28 17:12:59",
+ "last_d_time":"2026\/03\/28 17:10:29",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":295,
+ "lineprof_id":5,
+ "srvprof_id":0,
+ "ont_name":"SURIPTO",
+ "ont_sn":"HWTCa90b3c78",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-20.3160",
+ "last_u_time":"2026\/03\/23 16:53:17",
+ "last_d_time":"2026\/03\/23 16:51:38",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":297,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"HARIYANTO",
+ "ont_sn":"HWTCa90b5640",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-25.3780",
+ "last_u_time":"2026\/03\/28 17:23:32",
+ "last_d_time":"2026\/03\/28 17:22:08",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":298,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"SUGENG",
+ "ont_sn":"GGCL29764f25",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-20.3620",
+ "last_u_time":"2026\/03\/28 00:23:41",
+ "last_d_time":"2026\/03\/27 23:34:29",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":299,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"SATRIA PERUM PANGGUNG",
+ "ont_sn":"VSOL00ad34c5",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-30.0000",
+ "last_u_time":"2026\/02\/15 09:27:12",
+ "last_d_time":"2026\/02\/15 09:27:10",
+ "last_d_cause":"Power down",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":300,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"MALD\/H1\/3\/4\/1",
+ "ont_sn":"VSOL00adec6b",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-23.5660",
+ "last_u_time":"2026\/03\/24 08:41:10",
+ "last_d_time":"2026\/03\/24 08:37:43",
+ "last_d_cause":"",
+ "ont_description":"HENDRA KRISDIAN DELLY",
+ "parent":0
+ },
+ {
+ "identifier":301,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"BENI DWI PANGESTU",
+ "ont_sn":"VSOL00ad3667",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-20.8620",
+ "last_u_time":"2026\/03\/22 09:30:46",
+ "last_d_time":"2026\/03\/22 09:29:49",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":302,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"MALD\/H1\/1\/2\/10",
+ "ont_sn":"VSOL001a686e",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-23.1880",
+ "last_u_time":"2026\/03\/28 10:12:54",
+ "last_d_time":"2026\/03\/28 10:11:54",
+ "last_d_cause":"",
+ "ont_description":"WINDA-TALAS",
+ "parent":0
+ },
+ {
+ "identifier":303,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"VEGA\/MAMANG",
+ "ont_sn":"HWTCa90afa30",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-20.2700",
+ "last_u_time":"2026\/03\/28 14:40:52",
+ "last_d_time":"-",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":66048,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"ONT02\/000",
+ "ont_sn":"HWTCa41a909c",
+ "state":1,
+ "rstate":2,
+ "cstate":0,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-30.0000",
+ "last_u_time":"1970\/01\/01 06:01:45",
+ "last_d_time":"1970\/01\/01 06:02:39",
+ "last_d_cause":"Laser out",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":66049,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"ONT02\/001",
+ "ont_sn":"HWTCd1b3aa10",
+ "state":1,
+ "rstate":2,
+ "cstate":0,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-30.0000",
+ "last_u_time":"1970\/01\/01 06:04:34",
+ "last_d_time":"1970\/01\/01 06:07:20",
+ "last_d_cause":"Power down",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":66050,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"ONT02\/002",
+ "ont_sn":"HWTCd1b432d0",
+ "state":1,
+ "rstate":2,
+ "cstate":0,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-30.0000",
+ "last_u_time":"1970\/01\/01 06:14:02",
+ "last_d_time":"1970\/01\/01 06:14:52",
+ "last_d_cause":"Power down",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":66051,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"ONT02\/003",
+ "ont_sn":"ZTEGc676e674",
+ "state":1,
+ "rstate":2,
+ "cstate":0,
+ "mstate":0,
+ "dev_type":"SFU",
+ "receive_power":"-30.0000",
+ "last_u_time":"1970\/01\/01 06:15:37",
+ "last_d_time":"1970\/01\/01 06:18:47",
+ "last_d_cause":"Power down",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":66052,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"ONT02\/004",
+ "ont_sn":"HWTCc28ded9c",
+ "state":1,
+ "rstate":2,
+ "cstate":0,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-30.0000",
+ "last_u_time":"1970\/01\/01 06:18:02",
+ "last_d_time":"1970\/01\/01 06:19:10",
+ "last_d_cause":"Laser out",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":66053,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"ONT02\/005",
+ "ont_sn":"HWTC2781829a",
+ "state":1,
+ "rstate":2,
+ "cstate":0,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-30.0000",
+ "last_u_time":"1970\/01\/01 06:20:32",
+ "last_d_time":"1970\/01\/01 06:20:40",
+ "last_d_cause":"Laser out",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":66054,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"ONT02\/006",
+ "ont_sn":"HWTCd1b337a0",
+ "state":1,
+ "rstate":2,
+ "cstate":0,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-30.0000",
+ "last_u_time":"1970\/01\/01 06:23:23",
+ "last_d_time":"1970\/01\/01 06:25:24",
+ "last_d_cause":"Laser out",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":66055,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"ONT02\/007",
+ "ont_sn":"RTKG11111111",
+ "state":1,
+ "rstate":2,
+ "cstate":0,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-30.0000",
+ "last_u_time":"1970\/01\/01 06:30:45",
+ "last_d_time":"1970\/01\/01 06:31:23",
+ "last_d_cause":"Laser out",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":66057,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"ONT02\/009",
+ "ont_sn":"HWTCd1b37fc0",
+ "state":1,
+ "rstate":2,
+ "cstate":0,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-30.0000",
+ "last_u_time":"1970\/01\/01 06:32:44",
+ "last_d_time":"1970\/01\/01 06:34:50",
+ "last_d_cause":"Power down",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":66058,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"ONT02\/010",
+ "ont_sn":"HWTCd1b40ee8",
+ "state":1,
+ "rstate":2,
+ "cstate":0,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-30.0000",
+ "last_u_time":"1970\/01\/01 06:35:40",
+ "last_d_time":"1970\/01\/01 06:37:21",
+ "last_d_cause":"Power down",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":66059,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"ONT02\/011",
+ "ont_sn":"HWTCa90af7b8",
+ "state":1,
+ "rstate":2,
+ "cstate":0,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-30.0000",
+ "last_u_time":"1970\/01\/01 06:36:53",
+ "last_d_time":"1970\/01\/01 06:39:01",
+ "last_d_cause":"Laser out",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":66060,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"ONT02\/012",
+ "ont_sn":"HWTCa90b5570",
+ "state":1,
+ "rstate":2,
+ "cstate":0,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-30.0000",
+ "last_u_time":"1970\/01\/01 06:39:42",
+ "last_d_time":"1970\/01\/01 06:40:04",
+ "last_d_cause":"Laser out",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":66061,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"ONT02\/013",
+ "ont_sn":"ZTEGcd77423c",
+ "state":1,
+ "rstate":2,
+ "cstate":0,
+ "mstate":0,
+ "dev_type":"SFU",
+ "receive_power":"-30.0000",
+ "last_u_time":"1970\/01\/01 06:40:11",
+ "last_d_time":"1970\/01\/01 06:42:21",
+ "last_d_cause":"Power down",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":66062,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"ONT02\/014",
+ "ont_sn":"VSOL00ae998a",
+ "state":1,
+ "rstate":2,
+ "cstate":0,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-30.0000",
+ "last_u_time":"1970\/01\/08 08:28:12",
+ "last_d_time":"1970\/01\/09 04:02:46",
+ "last_d_cause":"Laser out",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":66063,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"ONT02\/015",
+ "ont_sn":"GPON00a19c71",
+ "state":1,
+ "rstate":2,
+ "cstate":0,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-30.0000",
+ "last_u_time":"1970\/01\/08 06:32:08",
+ "last_d_time":"1970\/01\/08 06:36:19",
+ "last_d_cause":"Power down",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":66064,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"ONT02\/016",
+ "ont_sn":"GPON00a16331",
+ "state":1,
+ "rstate":2,
+ "cstate":0,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-30.0000",
+ "last_u_time":"2025\/12\/29 13:45:04",
+ "last_d_time":"2025\/12\/29 13:54:08",
+ "last_d_cause":"Laser out",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":66065,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"ONT02\/017",
+ "ont_sn":"CDTCaf8e7c54",
+ "state":1,
+ "rstate":2,
+ "cstate":0,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-30.0000",
+ "last_u_time":"2025\/12\/29 13:22:20",
+ "last_d_time":"2025\/12\/29 13:54:08",
+ "last_d_cause":"Laser out",
+ "ont_description":"No-description",
+ "parent":0
+ },
+ {
+ "identifier":66066,
+ "lineprof_id":65535,
+ "srvprof_id":65535,
+ "ont_name":"ONT02\/018",
+ "ont_sn":"VSOL00afcc56",
+ "state":1,
+ "rstate":2,
+ "cstate":0,
+ "mstate":0,
+ "dev_type":"SFU",
+ "receive_power":"-30.0000",
+ "last_u_time":"-",
+ "last_d_time":"2026\/03\/10 14:46:56",
+ "last_d_cause":"Laser out",
+ "ont_description":"No-description",
+ "parent":0
+ }
+ ]
+}
\ No newline at end of file
diff --git a/api/debug_onu.json b/api/debug_onu.json
new file mode 100644
index 0000000..2271c50
--- /dev/null
+++ b/api/debug_onu.json
@@ -0,0 +1,1426 @@
+{
+ "code":1,
+ "message":"success",
+ "data":[
+ {
+ "identifier":256,
+ "onuspeed":0,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"ARTINI",
+ "ont_sn":"VSOL00addd35",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-25.6880",
+ "last_u_time":"2020\/09\/27 20:18:32+07:00",
+ "last_d_time":"2020\/09\/27 20:17:35+07:00",
+ "last_d_cause":"",
+ "ont_description":"ARTINI",
+ "parent":0,
+ "distance":390
+ },
+ {
+ "identifier":1048833,
+ "onuspeed":1,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"SATRIA PERUM PANGGUNG",
+ "ont_sn":"VSOL00ad1105",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-24.4380",
+ "last_u_time":"2020\/09\/28 05:07:45+07:00",
+ "last_d_time":"2020\/09\/28 05:06:15+07:00",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":2754
+ },
+ {
+ "identifier":258,
+ "onuspeed":0,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"RIDA AGUS",
+ "ont_sn":"HWTCa90adda0",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-21.3100",
+ "last_u_time":"2020\/09\/26 22:40:26+07:00",
+ "last_d_time":"-",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":298
+ },
+ {
+ "identifier":259,
+ "onuspeed":0,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"SMP 6 SITUBONDO",
+ "ont_sn":"HWTCa90add88",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-21.4280",
+ "last_u_time":"2020\/09\/26 22:40:26+07:00",
+ "last_d_time":"-",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":358
+ },
+ {
+ "identifier":1048836,
+ "onuspeed":1,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"BASRIYADI",
+ "ont_sn":"HWTCa90aaf00",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-21.0240",
+ "last_u_time":"2020\/09\/28 05:08:36+07:00",
+ "last_d_time":"2020\/09\/28 05:06:16+07:00",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":2441
+ },
+ {
+ "identifier":261,
+ "onuspeed":0,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"IRWAN",
+ "ont_sn":"HWTCd1b3aa28",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-22.2200",
+ "last_u_time":"2020\/09\/26 22:39:44+07:00",
+ "last_d_time":"-",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":345
+ },
+ {
+ "identifier":262,
+ "onuspeed":0,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"TEGUH ADI",
+ "ont_sn":"HWTCa90a4760",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-21.1360",
+ "last_u_time":"2020\/09\/26 22:40:36+07:00",
+ "last_d_time":"-",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":294
+ },
+ {
+ "identifier":1048839,
+ "onuspeed":1,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"MALD\/H1\/1\/3\/13",
+ "ont_sn":"CDTCaf8e7bf1",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-22.5200",
+ "last_u_time":"2020\/09\/27 08:49:20+07:00",
+ "last_d_time":"2020\/09\/27 04:47:01+07:00",
+ "last_d_cause":"",
+ "ont_description":"BAGOES-FARIZNA",
+ "parent":0,
+ "distance":429
+ },
+ {
+ "identifier":264,
+ "onuspeed":0,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"FENTI",
+ "ont_sn":"HWTCa90aaed8",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-21.5500",
+ "last_u_time":"2020\/09\/26 22:40:27+07:00",
+ "last_d_time":"-",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":351
+ },
+ {
+ "identifier":265,
+ "onuspeed":0,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"DESY\/SUPARJO",
+ "ont_sn":"HWTCa90aabf8",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-22.4420",
+ "last_u_time":"2020\/09\/27 11:59:01+07:00",
+ "last_d_time":"2020\/09\/27 11:57:34+07:00",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":426
+ },
+ {
+ "identifier":266,
+ "onuspeed":0,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"DIFTA DWI",
+ "ont_sn":"HWTCd1b32230",
+ "state":0,
+ "rstate":0,
+ "cstate":0,
+ "mstate":0,
+ "dev_type":"SFU",
+ "receive_power":"-30.0000",
+ "last_u_time":"-",
+ "last_d_time":"-",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":0
+ },
+ {
+ "identifier":267,
+ "onuspeed":0,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"AYANG",
+ "ont_sn":"HWTCa90addb0",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-20.7060",
+ "last_u_time":"2020\/09\/26 22:40:44+07:00",
+ "last_d_time":"-",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":301
+ },
+ {
+ "identifier":268,
+ "onuspeed":0,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"TIO",
+ "ont_sn":"HWTCd1b40e20",
+ "state":0,
+ "rstate":0,
+ "cstate":0,
+ "mstate":0,
+ "dev_type":"SFU",
+ "receive_power":"-30.0000",
+ "last_u_time":"-",
+ "last_d_time":"-",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":0
+ },
+ {
+ "identifier":269,
+ "onuspeed":0,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"ADIT",
+ "ont_sn":"HWTCd1b34100",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-22.1480",
+ "last_u_time":"2020\/09\/28 02:15:59+07:00",
+ "last_d_time":"2020\/09\/28 02:14:41+07:00",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":310
+ },
+ {
+ "identifier":270,
+ "onuspeed":0,
+ "lineprof_id":2,
+ "srvprof_id":0,
+ "ont_name":"VEGA\/MAMANG",
+ "ont_sn":"ZXICaefca657",
+ "state":0,
+ "rstate":0,
+ "cstate":0,
+ "mstate":0,
+ "dev_type":"SFU",
+ "receive_power":"-30.0000",
+ "last_u_time":"-",
+ "last_d_time":"-",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":0
+ },
+ {
+ "identifier":271,
+ "onuspeed":0,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"AZKA",
+ "ont_sn":"HWTCa90a5b00",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-23.9800",
+ "last_u_time":"2020\/09\/26 22:40:37+07:00",
+ "last_d_time":"-",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":365
+ },
+ {
+ "identifier":272,
+ "onuspeed":0,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"DIMAS OLEAN",
+ "ont_sn":"HWTCd1b1bf80",
+ "state":0,
+ "rstate":0,
+ "cstate":0,
+ "mstate":0,
+ "dev_type":"SFU",
+ "receive_power":"-30.0000",
+ "last_u_time":"-",
+ "last_d_time":"-",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":0
+ },
+ {
+ "identifier":273,
+ "onuspeed":0,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"ASWA",
+ "ont_sn":"HWTCa90a9808",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-20.3640",
+ "last_u_time":"2020\/09\/26 22:40:35+07:00",
+ "last_d_time":"-",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":284
+ },
+ {
+ "identifier":274,
+ "onuspeed":0,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"ZAINUL",
+ "ont_sn":"HWTCd1b35cc8",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-22.0780",
+ "last_u_time":"2020\/09\/26 22:40:05+07:00",
+ "last_d_time":"-",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":258
+ },
+ {
+ "identifier":275,
+ "onuspeed":0,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"PAK JONO",
+ "ont_sn":"HWTCa90af408",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-20.6060",
+ "last_u_time":"2020\/09\/28 06:47:20+07:00",
+ "last_d_time":"2020\/09\/28 06:47:12+07:00",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":351
+ },
+ {
+ "identifier":276,
+ "onuspeed":0,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"DAVID",
+ "ont_sn":"HWTCd1b35928",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-20.8620",
+ "last_u_time":"2020\/09\/26 22:39:48+07:00",
+ "last_d_time":"-",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":289
+ },
+ {
+ "identifier":277,
+ "onuspeed":0,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"DIKI",
+ "ont_sn":"HWTCd1b34b38",
+ "state":0,
+ "rstate":0,
+ "cstate":0,
+ "mstate":0,
+ "dev_type":"SFU",
+ "receive_power":"-30.0000",
+ "last_u_time":"-",
+ "last_d_time":"-",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":0
+ },
+ {
+ "identifier":278,
+ "onuspeed":0,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"AZKA TOKO",
+ "ont_sn":"HWTCa90b9ee0",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-20.7580",
+ "last_u_time":"2020\/09\/26 22:40:43+07:00",
+ "last_d_time":"-",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":409
+ },
+ {
+ "identifier":279,
+ "onuspeed":0,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"PAK GAGUK",
+ "ont_sn":"HWTCa90addb8",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-24.3180",
+ "last_u_time":"2020\/09\/26 22:40:33+07:00",
+ "last_d_time":"-",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":350
+ },
+ {
+ "identifier":1048856,
+ "onuspeed":1,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"IKE PUJI",
+ "ont_sn":"HWTCa90b1170",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-18.8620",
+ "last_u_time":"2020\/09\/28 05:08:20+07:00",
+ "last_d_time":"2020\/09\/28 05:06:15+07:00",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":2323
+ },
+ {
+ "identifier":1048857,
+ "onuspeed":1,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"VINGGO",
+ "ont_sn":"HWTCa90a47b0",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-24.2040",
+ "last_u_time":"2020\/09\/28 01:06:13+07:00",
+ "last_d_time":"2020\/09\/28 00:12:59+07:00",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":391
+ },
+ {
+ "identifier":282,
+ "onuspeed":0,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"DEWI DKITE",
+ "ont_sn":"CDTCaf8e7c0c",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-14.4860",
+ "last_u_time":"2020\/09\/26 22:39:41+07:00",
+ "last_d_time":"-",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":889
+ },
+ {
+ "identifier":283,
+ "onuspeed":0,
+ "lineprof_id":2,
+ "srvprof_id":0,
+ "ont_name":"CCTV_TALAS",
+ "ont_sn":"HWTCa90a5520",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-23.1000",
+ "last_u_time":"2020\/09\/26 22:40:52+07:00",
+ "last_d_time":"-",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":296
+ },
+ {
+ "identifier":284,
+ "onuspeed":0,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"EKI",
+ "ont_sn":"HWTCa90a46b8",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-24.2040",
+ "last_u_time":"2020\/09\/26 22:41:16+07:00",
+ "last_d_time":"-",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":360
+ },
+ {
+ "identifier":285,
+ "onuspeed":0,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"ALEX",
+ "ont_sn":"HWTCa90b4c38",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-24.5600",
+ "last_u_time":"2020\/09\/26 22:40:43+07:00",
+ "last_d_time":"-",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":372
+ },
+ {
+ "identifier":1048862,
+ "onuspeed":1,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"TOLAK SAFARI",
+ "ont_sn":"CDTCaf8ee4ff",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-19.9580",
+ "last_u_time":"2020\/09\/28 05:07:33+07:00",
+ "last_d_time":"2020\/09\/28 05:06:15+07:00",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":2611
+ },
+ {
+ "identifier":1048863,
+ "onuspeed":1,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"NURHIDAYAT",
+ "ont_sn":"ELWGc6b0a547",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-19.9100",
+ "last_u_time":"2020\/09\/28 05:07:59+07:00",
+ "last_d_time":"2020\/09\/28 05:06:16+07:00",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":1357
+ },
+ {
+ "identifier":288,
+ "onuspeed":0,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"CHOIRUL ANWAR",
+ "ont_sn":"CDTCaf8e7bfa",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-15.8840",
+ "last_u_time":"2020\/09\/26 18:50:58+07:00",
+ "last_d_time":"-",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":977
+ },
+ {
+ "identifier":1048865,
+ "onuspeed":1,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"AFIF",
+ "ont_sn":"HWTCd1b37980",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-19.1020",
+ "last_u_time":"2020\/09\/28 05:07:34+07:00",
+ "last_d_time":"2020\/09\/28 05:06:15+07:00",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":1293
+ },
+ {
+ "identifier":1048866,
+ "onuspeed":1,
+ "lineprof_id":5,
+ "srvprof_id":0,
+ "ont_name":"AINI",
+ "ont_sn":"HWTCa90a5558",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-17.6720",
+ "last_u_time":"2020\/09\/28 05:08:12+07:00",
+ "last_d_time":"2020\/09\/28 05:06:15+07:00",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":1490
+ },
+ {
+ "identifier":291,
+ "onuspeed":0,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"EKA",
+ "ont_sn":"CDTCaf8e7c03",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-23.3740",
+ "last_u_time":"2020\/09\/26 22:39:32+07:00",
+ "last_d_time":"-",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":443
+ },
+ {
+ "identifier":292,
+ "onuspeed":0,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"ONT01\/036",
+ "ont_sn":"ZTEGcf5ac619",
+ "state":0,
+ "rstate":0,
+ "cstate":0,
+ "mstate":0,
+ "dev_type":"SFU",
+ "receive_power":"-30.0000",
+ "last_u_time":"-",
+ "last_d_time":"-",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":0
+ },
+ {
+ "identifier":1048870,
+ "onuspeed":1,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"PUTRI WULANSARI",
+ "ont_sn":"HWTCa90a5350",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-20.5560",
+ "last_u_time":"2020\/09\/28 05:08:03+07:00",
+ "last_d_time":"2020\/09\/28 05:06:16+07:00",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":2939
+ },
+ {
+ "identifier":1048871,
+ "onuspeed":1,
+ "lineprof_id":5,
+ "srvprof_id":0,
+ "ont_name":"SURIPTO",
+ "ont_sn":"HWTCa90b3c78",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-20.9160",
+ "last_u_time":"2020\/09\/28 05:08:05+07:00",
+ "last_d_time":"2020\/09\/28 05:06:16+07:00",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":2523
+ },
+ {
+ "identifier":296,
+ "onuspeed":0,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"DIMAS",
+ "ont_sn":"GGCL298413e0",
+ "state":0,
+ "rstate":0,
+ "cstate":0,
+ "mstate":0,
+ "dev_type":"SFU",
+ "receive_power":"-30.0000",
+ "last_u_time":"-",
+ "last_d_time":"-",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":0
+ },
+ {
+ "identifier":1048873,
+ "onuspeed":1,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"HARIYANTO",
+ "ont_sn":"HWTCa90b5640",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-26.9900",
+ "last_u_time":"2020\/09\/28 05:08:12+07:00",
+ "last_d_time":"2020\/09\/28 05:06:15+07:00",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":3075
+ },
+ {
+ "identifier":1048874,
+ "onuspeed":1,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"SUGENG",
+ "ont_sn":"GGCL29764f25",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-22.0700",
+ "last_u_time":"2020\/09\/28 05:08:01+07:00",
+ "last_d_time":"2020\/09\/28 05:06:16+07:00",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":3265
+ },
+ {
+ "identifier":299,
+ "onuspeed":0,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"ONT01\/043",
+ "ont_sn":"VSOL00ad34c5",
+ "state":0,
+ "rstate":0,
+ "cstate":0,
+ "mstate":0,
+ "dev_type":"SFU",
+ "receive_power":"-30.0000",
+ "last_u_time":"-",
+ "last_d_time":"-",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":0
+ },
+ {
+ "identifier":1048876,
+ "onuspeed":1,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"MALD\/H1\/3\/4\/1",
+ "ont_sn":"VSOL00adec6b",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-23.8740",
+ "last_u_time":"2020\/09\/28 05:07:48+07:00",
+ "last_d_time":"2020\/09\/28 05:06:16+07:00",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":2920
+ },
+ {
+ "identifier":301,
+ "onuspeed":0,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"BENI DWI PANGESTU",
+ "ont_sn":"VSOL00ad3667",
+ "state":0,
+ "rstate":0,
+ "cstate":0,
+ "mstate":0,
+ "dev_type":"SFU",
+ "receive_power":"-30.0000",
+ "last_u_time":"-",
+ "last_d_time":"-",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":0
+ },
+ {
+ "identifier":302,
+ "onuspeed":0,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"MALD\/H1\/1\/2\/10",
+ "ont_sn":"VSOL001a686e",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-23.4680",
+ "last_u_time":"2020\/09\/26 22:40:09+07:00",
+ "last_d_time":"2020\/09\/26 22:39:03+07:00",
+ "last_d_cause":"",
+ "ont_description":"WINDA-TALAS",
+ "parent":0,
+ "distance":323
+ },
+ {
+ "identifier":1048879,
+ "onuspeed":1,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"VEGA\/MAMANG",
+ "ont_sn":"HWTCa90afa30",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-21.8060",
+ "last_u_time":"2020\/09\/28 05:08:20+07:00",
+ "last_d_time":"2020\/09\/28 05:06:16+07:00",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":3533
+ },
+ {
+ "identifier":1048880,
+ "onuspeed":1,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"ONT01\/048",
+ "ont_sn":"GPON00a13ee1",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-22.7580",
+ "last_u_time":"2020\/09\/28 05:07:45+07:00",
+ "last_d_time":"2020\/09\/28 05:06:16+07:00",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":3651
+ },
+ {
+ "identifier":305,
+ "onuspeed":0,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"DIKI TALAS",
+ "ont_sn":"ELWGc6b7d18c",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-20.0700",
+ "last_u_time":"2020\/09\/26 22:40:04+07:00",
+ "last_d_time":"-",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":371
+ },
+ {
+ "identifier":306,
+ "onuspeed":0,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"DIFTA",
+ "ont_sn":"ELWGc6f9c2a7",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-28.5020",
+ "last_u_time":"2020\/09\/26 22:39:56+07:00",
+ "last_d_time":"-",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":346
+ },
+ {
+ "identifier":1048883,
+ "onuspeed":1,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"TIO TALAS",
+ "ont_sn":"CDTCaf53046e",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-20.9700",
+ "last_u_time":"2020\/09\/27 19:04:56+07:00",
+ "last_d_time":"2020\/09\/27 17:17:02+07:00",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":279
+ },
+ {
+ "identifier":512,
+ "onuspeed":0,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"ONT02\/000",
+ "ont_sn":"HWTCa41a909c",
+ "state":0,
+ "rstate":0,
+ "cstate":0,
+ "mstate":0,
+ "dev_type":"SFU",
+ "receive_power":"-30.0000",
+ "last_u_time":"-",
+ "last_d_time":"-",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":0
+ },
+ {
+ "identifier":513,
+ "onuspeed":0,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"ONT02\/001",
+ "ont_sn":"HWTCd1b3aa10",
+ "state":0,
+ "rstate":0,
+ "cstate":0,
+ "mstate":0,
+ "dev_type":"SFU",
+ "receive_power":"-30.0000",
+ "last_u_time":"-",
+ "last_d_time":"-",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":0
+ },
+ {
+ "identifier":514,
+ "onuspeed":0,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"ONT02\/002",
+ "ont_sn":"HWTCd1b432d0",
+ "state":0,
+ "rstate":0,
+ "cstate":0,
+ "mstate":0,
+ "dev_type":"SFU",
+ "receive_power":"-30.0000",
+ "last_u_time":"-",
+ "last_d_time":"-",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":0
+ },
+ {
+ "identifier":515,
+ "onuspeed":0,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"ONT02\/003",
+ "ont_sn":"ZTEGc676e674",
+ "state":0,
+ "rstate":0,
+ "cstate":0,
+ "mstate":0,
+ "dev_type":"SFU",
+ "receive_power":"-30.0000",
+ "last_u_time":"-",
+ "last_d_time":"-",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":0
+ },
+ {
+ "identifier":516,
+ "onuspeed":0,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"ONT02\/004",
+ "ont_sn":"HWTCc28ded9c",
+ "state":0,
+ "rstate":0,
+ "cstate":0,
+ "mstate":0,
+ "dev_type":"SFU",
+ "receive_power":"-30.0000",
+ "last_u_time":"-",
+ "last_d_time":"-",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":0
+ },
+ {
+ "identifier":517,
+ "onuspeed":0,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"ONT02\/005",
+ "ont_sn":"HWTC2781829a",
+ "state":0,
+ "rstate":0,
+ "cstate":0,
+ "mstate":0,
+ "dev_type":"SFU",
+ "receive_power":"-30.0000",
+ "last_u_time":"-",
+ "last_d_time":"-",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":0
+ },
+ {
+ "identifier":518,
+ "onuspeed":0,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"ONT02\/006",
+ "ont_sn":"HWTCd1b337a0",
+ "state":0,
+ "rstate":0,
+ "cstate":0,
+ "mstate":0,
+ "dev_type":"SFU",
+ "receive_power":"-30.0000",
+ "last_u_time":"-",
+ "last_d_time":"-",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":0
+ },
+ {
+ "identifier":519,
+ "onuspeed":0,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"ONT02\/007",
+ "ont_sn":"RTKG11111111",
+ "state":0,
+ "rstate":0,
+ "cstate":0,
+ "mstate":0,
+ "dev_type":"SFU",
+ "receive_power":"-30.0000",
+ "last_u_time":"-",
+ "last_d_time":"-",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":0
+ },
+ {
+ "identifier":520,
+ "onuspeed":0,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"ONT02\/008",
+ "ont_sn":"HWTCa90b5660",
+ "state":0,
+ "rstate":0,
+ "cstate":0,
+ "mstate":0,
+ "dev_type":"SFU",
+ "receive_power":"-30.0000",
+ "last_u_time":"-",
+ "last_d_time":"-",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":0
+ },
+ {
+ "identifier":521,
+ "onuspeed":0,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"ONT02\/009",
+ "ont_sn":"HWTCd1b37fc0",
+ "state":0,
+ "rstate":0,
+ "cstate":0,
+ "mstate":0,
+ "dev_type":"SFU",
+ "receive_power":"-30.0000",
+ "last_u_time":"-",
+ "last_d_time":"-",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":0
+ },
+ {
+ "identifier":522,
+ "onuspeed":0,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"ONT02\/010",
+ "ont_sn":"HWTCd1b40ee8",
+ "state":0,
+ "rstate":0,
+ "cstate":0,
+ "mstate":0,
+ "dev_type":"SFU",
+ "receive_power":"-30.0000",
+ "last_u_time":"-",
+ "last_d_time":"-",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":0
+ },
+ {
+ "identifier":523,
+ "onuspeed":0,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"ONT02\/011",
+ "ont_sn":"HWTCa90af7b8",
+ "state":0,
+ "rstate":0,
+ "cstate":0,
+ "mstate":0,
+ "dev_type":"SFU",
+ "receive_power":"-30.0000",
+ "last_u_time":"-",
+ "last_d_time":"-",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":0
+ },
+ {
+ "identifier":524,
+ "onuspeed":0,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"ONT02\/012",
+ "ont_sn":"HWTCa90b5570",
+ "state":0,
+ "rstate":0,
+ "cstate":0,
+ "mstate":0,
+ "dev_type":"SFU",
+ "receive_power":"-30.0000",
+ "last_u_time":"-",
+ "last_d_time":"-",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":0
+ },
+ {
+ "identifier":525,
+ "onuspeed":0,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"ONT02\/013",
+ "ont_sn":"ZTEGcd77423c",
+ "state":0,
+ "rstate":0,
+ "cstate":0,
+ "mstate":0,
+ "dev_type":"SFU",
+ "receive_power":"-30.0000",
+ "last_u_time":"-",
+ "last_d_time":"-",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":0
+ },
+ {
+ "identifier":526,
+ "onuspeed":0,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"ONT02\/014",
+ "ont_sn":"VSOL00ae998a",
+ "state":0,
+ "rstate":0,
+ "cstate":0,
+ "mstate":0,
+ "dev_type":"SFU",
+ "receive_power":"-30.0000",
+ "last_u_time":"-",
+ "last_d_time":"-",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":0
+ },
+ {
+ "identifier":527,
+ "onuspeed":0,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"ONT02\/015",
+ "ont_sn":"GPON00a19c71",
+ "state":0,
+ "rstate":0,
+ "cstate":0,
+ "mstate":0,
+ "dev_type":"SFU",
+ "receive_power":"-30.0000",
+ "last_u_time":"-",
+ "last_d_time":"-",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":0
+ },
+ {
+ "identifier":528,
+ "onuspeed":0,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"ONT02\/016",
+ "ont_sn":"GPON00a16331",
+ "state":0,
+ "rstate":0,
+ "cstate":0,
+ "mstate":0,
+ "dev_type":"SFU",
+ "receive_power":"-30.0000",
+ "last_u_time":"-",
+ "last_d_time":"-",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":0
+ },
+ {
+ "identifier":529,
+ "onuspeed":0,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"ONT02\/017",
+ "ont_sn":"CDTCaf8e7c54",
+ "state":0,
+ "rstate":0,
+ "cstate":0,
+ "mstate":0,
+ "dev_type":"SFU",
+ "receive_power":"-30.0000",
+ "last_u_time":"-",
+ "last_d_time":"-",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":0
+ },
+ {
+ "identifier":1049106,
+ "onuspeed":1,
+ "lineprof_id":0,
+ "srvprof_id":0,
+ "ont_name":"NURHIDAYAT",
+ "ont_sn":"CDTCaf8ee4ed",
+ "state":1,
+ "rstate":1,
+ "cstate":1,
+ "mstate":0,
+ "dev_type":"HGU",
+ "receive_power":"-24.2040",
+ "last_u_time":"2020\/09\/29 01:42:56+07:00",
+ "last_d_time":"2020\/09\/29 01:35:56+07:00",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":208
+ },
+ {
+ "identifier":531,
+ "onuspeed":0,
+ "lineprof_id":1,
+ "srvprof_id":0,
+ "ont_name":"ONT02\/019",
+ "ont_sn":"HWTCd1b19ac8",
+ "state":0,
+ "rstate":0,
+ "cstate":0,
+ "mstate":0,
+ "dev_type":"SFU",
+ "receive_power":"-30.0000",
+ "last_u_time":"-",
+ "last_d_time":"-",
+ "last_d_cause":"",
+ "ont_description":"No-description",
+ "parent":0,
+ "distance":0
+ }
+ ]
+}
\ No newline at end of file
diff --git a/api/detail_redaman-bc.txt b/api/detail_redaman-bc.txt
new file mode 100644
index 0000000..d5331e2
--- /dev/null
+++ b/api/detail_redaman-bc.txt
@@ -0,0 +1,95 @@
+getConnection();
+
+$id = intval($_GET['id'] ?? 0);
+if ($id <= 0) {
+ echo json_encode(['success'=>false,'message'=>'ID tidak valid']);
+ exit;
+}
+
+$stmt = $conn->prepare("SELECT serial_number FROM ftth_items WHERE id=:id");
+$stmt->bindParam(':id', $id, PDO::PARAM_INT);
+$stmt->execute();
+$row = $stmt->fetch(PDO::FETCH_ASSOC);
+
+if (!$row) {
+ echo json_encode(['success'=>false,'message'=>'Data tidak ditemukan']);
+ exit;
+}
+
+$serialNumber = $row['serial_number'];
+
+// Default nilai
+$rxPower = null;
+$pppoeIP = null;
+$voltage = null;
+$uptime = null;
+$inform = null;
+
+if ($serialNumber) {
+ $query = json_encode(["_id" => $serialNumber]);
+ $url = "http://rmtstb.megadataisp.net:7557/devices/?query=" . urlencode($query);
+
+ $ch = curl_init();
+ curl_setopt($ch, CURLOPT_URL, $url);
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+ $response = curl_exec($ch);
+ curl_close($ch);
+
+ if ($response) {
+ $data = json_decode($response, true);
+
+ if (isset($data[0])) {
+
+ // RX Power
+ if (isset($data[0]['VirtualParameters']['RXPower']['_value'])) {
+ $rxPower = $data[0]['VirtualParameters']['RXPower']['_value'] . " dBm";
+ }
+
+ // PPPoE IP
+ if (isset($data[0]['VirtualParameters']['pppoeIP']['_value'])) {
+ $pppoeIP = $data[0]['VirtualParameters']['pppoeIP']['_value'];
+ }
+
+ // Voltage (VP)
+ if (isset($data[0]['VirtualParameters']['Voltage']['_value'])) {
+ $rawVoltage = $data[0]['VirtualParameters']['Voltage']['_value'];
+
+ // konversi ke Volt (dibagi 10000)
+ $voltageConvert = $rawVoltage / 10000;
+
+ // ambil 2 angka belakang
+ $voltage = number_format($voltageConvert, 2) . " V";
+}
+
+ // Uptime (detik → HH:MM:SS)
+ if (isset($data[0]['InternetGatewayDevice']['DeviceInfo']['UpTime']['_value'])) {
+ $seconds = (int)$data[0]['InternetGatewayDevice']['DeviceInfo']['UpTime']['_value'];
+ $uptime = gmdate("H:i:s", $seconds);
+ }
+
+ // Inform terakhir
+ if (isset($data[0]['Events']['Inform'])) {
+ $inform = $data[0]['Events']['Inform'];
+ }
+ }
+ }
+}
+
+// Output JSON
+echo json_encode([
+ 'success' => true,
+ 'data' => [
+ 'serial_number' => $serialNumber,
+ 'rx_power' => $rxPower ?? 'Tidak tersedia',
+ 'pppoe_ip' => $pppoeIP ?? 'Tidak tersedia',
+ 'voltage' => $voltage ?? 'Tidak tersedia',
+ 'uptime' => $uptime ?? 'Tidak tersedia',
+ 'inform' => $inform ?? 'Tidak tersedia'
+ ]
+]);
diff --git a/api/detail_redaman.php b/api/detail_redaman.php
index f59b3de..6fb7f14 100644
--- a/api/detail_redaman.php
+++ b/api/detail_redaman.php
@@ -1,19 +1,47 @@
getConnection();
+// ======================
+// 🔥 TEST MODE
+// ======================
+// url test : http://localhost/ftthplanner/api/detail_redaman.php?id=859
+$TEST_MODE = true;
+
+$TEST_DATA = [
+ "08A5AE-F609-ZXIC6A7451C337D" => [
+ "rx" => -23,
+ "volt" => 2.9
+ ],
+ //id 836 Client putri 081252188305 sn : GGCL298413e0
+ "08A5AE-F609-ZXIC03C33C4B433" => [
+ "rx" => -32,
+ "volt" => 3.2
+ ],
+ //id : 859 difta dwi RT via kantor sn : CDTCaf8ee4ed
+ "08A5AE-F609-ZXIC1D6EF05BDD7" => [
+ "rx" => -28,
+ "volt" => 3.2
+ ],
+];
+
+// ======================
+// 🔥 VALIDASI ID
+// ======================
$id = intval($_GET['id'] ?? 0);
if ($id <= 0) {
echo json_encode(['success'=>false,'message'=>'ID tidak valid']);
exit;
}
+// ======================
+// 🔥 AMBIL SN
+// ======================
$stmt = $conn->prepare("SELECT serial_number FROM ftth_items WHERE id=:id");
$stmt->bindParam(':id', $id, PDO::PARAM_INT);
$stmt->execute();
@@ -24,43 +52,100 @@ if (!$row) {
exit;
}
-$serialNumber = $row['serial_number'];
+// 🔥 NORMALISASI SN
+$serialNumber = strtoupper(trim($row['serial_number']));
-// Ambil RX Power dan PPPoE IP dari API
+// ======================
+// 🔥 DEFAULT
+// ======================
$rxPower = null;
$pppoeIP = null;
+$voltage = null;
+$uptime = null;
+$inform = null;
-if ($serialNumber) {
- $query = json_encode(["_id" => $serialNumber]);
- $url = "http://localhost:7557/devices/?query=" . urlencode($query);
+// ======================
+// 🔥 CEK: MANUAL ATAU AUTO
+// ======================
+$useManual = ($TEST_MODE && isset($TEST_DATA[$serialNumber]));
- $ch = curl_init();
- curl_setopt($ch, CURLOPT_URL, $url);
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
- $response = curl_exec($ch);
- curl_close($ch);
+if ($useManual) {
- if ($response) {
- $data = json_decode($response, true);
+ // ======================
+ // 🔥 MODE MANUAL (HANYA SN YANG ADA DI TEST_DATA)
+ // ======================
+ $rxPower = $TEST_DATA[$serialNumber]['rx'] . " dBm";
+ $voltage = number_format($TEST_DATA[$serialNumber]['volt'], 2) . " V";
- // Ambil RX Power
- if (isset($data[0]['VirtualParameters']['RXPower']['_value'])) {
- $rxPower = $data[0]['VirtualParameters']['RXPower']['_value'] . " dBm";
- }
+ $pppoeIP = "TEST MODE";
+ $uptime = "-";
+ $inform = "MANUAL";
- // Ambil PPPoE IP
- if (isset($data[0]['VirtualParameters']['pppoeIP']['_value'])) {
- $pppoeIP = $data[0]['VirtualParameters']['pppoeIP']['_value'];
+} else {
+
+ // ======================
+ // 🔥 MODE AUTO (GENIEACS)
+ // ======================
+ if ($serialNumber) {
+
+ $query = json_encode(["_id" => $serialNumber]);
+ $url = "http://rmtstb.megadataisp.net:7557/devices/?query=" . urlencode($query);
+
+ $ch = curl_init();
+ curl_setopt($ch, CURLOPT_URL, $url);
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($ch, CURLOPT_TIMEOUT, 5);
+ $response = curl_exec($ch);
+ curl_close($ch);
+
+ if ($response) {
+ $data = json_decode($response, true);
+
+ if (isset($data[0])) {
+
+ // RX
+ if (isset($data[0]['VirtualParameters']['RXPower']['_value'])) {
+ $rxPower = $data[0]['VirtualParameters']['RXPower']['_value'] . " dBm";
+ }
+
+ // PPPoE
+ if (isset($data[0]['VirtualParameters']['pppoeIP']['_value'])) {
+ $pppoeIP = $data[0]['VirtualParameters']['pppoeIP']['_value'];
+ }
+
+ // Voltage
+ if (isset($data[0]['VirtualParameters']['Voltage']['_value'])) {
+ $rawVoltage = $data[0]['VirtualParameters']['Voltage']['_value'];
+ $voltageConvert = $rawVoltage / 10000;
+ $voltage = number_format($voltageConvert, 2) . " V";
+ }
+
+ // Uptime
+ if (isset($data[0]['InternetGatewayDevice']['DeviceInfo']['UpTime']['_value'])) {
+ $seconds = (int)$data[0]['InternetGatewayDevice']['DeviceInfo']['UpTime']['_value'];
+ $uptime = gmdate("H:i:s", $seconds);
+ }
+
+ // Inform
+ if (isset($data[0]['Events']['Inform'])) {
+ $inform = $data[0]['Events']['Inform'];
+ }
+ }
}
}
}
-// Output JSON untuk AJAX
+// ======================
+// 🔥 OUTPUT
+// ======================
echo json_encode([
'success' => true,
'data' => [
'serial_number' => $serialNumber,
'rx_power' => $rxPower ?? 'Tidak tersedia',
- 'pppoe_ip' => $pppoeIP ?? 'Tidak tersedia'
+ 'pppoe_ip' => $pppoeIP ?? 'Tidak tersedia',
+ 'voltage' => $voltage ?? 'Tidak tersedia',
+ 'uptime' => $uptime ?? 'Tidak tersedia',
+ 'inform' => $inform ?? 'Tidak tersedia'
]
-]);
+]);
\ No newline at end of file
diff --git a/api/deteksi loss b/api/deteksi loss
new file mode 100644
index 0000000..e69de29
diff --git a/api/generate.php b/api/generate.php
new file mode 100644
index 0000000..5f15948
--- /dev/null
+++ b/api/generate.php
@@ -0,0 +1,62 @@
+ 'VSOL00addd35', 'name' => 'ARTINI', 'rx' => -25.5300, 'volt' => 3.24],
+ ['sn' => 'VSOL00ad1105', 'name' => 'SATRIA PERUM PANGGUNG', 'rx' => -24.3180, 'volt' => 3.26],
+ ['sn' => 'HWTCa90adda0', 'name' => 'RIDA AGUS', 'rx' => -21.2500, 'volt' => 3.24],
+ ['sn' => 'HWTCa90add88', 'name' => 'SMP 6 SITUBONDO', 'rx' => -21.4280, 'volt' => 3.26],
+ ['sn' => 'HWTCa90aaf00', 'name' => 'BASRIYADI', 'rx' => -21.1360, 'volt' => 3.26],
+ ['sn' => 'HWTCd1b3aa28', 'name' => 'IRWAN', 'rx' => -22.0780, 'volt' => 3.28],
+ ['sn' => 'HWTCa90a4760', 'name' => 'TEGUH ADI', 'rx' => -21.0240, 'volt' => 3.24],
+ ['sn' => 'CDTCaf8e7bf1', 'name' => 'MALD/H1/1/3/13', 'rx' => -22.4420, 'volt' => 3.30],
+ ['sn' => 'HWTCa90aaed8', 'name' => 'FENTI', 'rx' => -21.4280, 'volt' => 3.28],
+ ['sn' => 'HWTCa90aabf8', 'name' => 'DESY/SUPARJO', 'rx' => -22.2920, 'volt' => 3.28],
+ ['sn' => 'HWTCa90addb0', 'name' => 'AYANG', 'rx' => -20.6060, 'volt' => 3.22],
+];
+
+$dates = [];
+for ($d = 12; $d <= 19; $d++) {
+ $dates[] = "2026-06-" . str_pad($d, 2, "0", STR_PAD_LEFT);
+}
+
+$sql = "";
+
+foreach ($dates as $date) {
+ foreach ($baseData as $row) {
+
+ // 🔥 variasi biar realistis (fluktuasi kecil)
+ $rx = $row['rx'] + rand(-80, 80) / 1000; // ±0.08 dBm
+ $volt = $row['volt'] + rand(-5, 5) / 1000; // ±0.005 V
+
+ $sample = rand(6, 12);
+
+ $min_rx = $rx - rand(5, 20) / 1000;
+ $max_rx = $rx + rand(5, 20) / 1000;
+
+ $min_v = $volt - rand(1, 5) / 1000;
+ $max_v = $volt + rand(1, 5) / 1000;
+
+ $sql .= "INSERT INTO onu_daily_history
+(sn, ont_name, rx_power, voltage, min_rx, max_rx, min_voltage, max_voltage, last_cause, sample_count, log_date, created_at, updated_at)
+VALUES
+(
+'{$row['sn']}',
+'{$row['name']}',
+" . round($rx, 4) . ",
+" . round($volt, 3) . ",
+" . round($min_rx, 4) . ",
+" . round($max_rx, 4) . ",
+" . round($min_v, 3) . ",
+" . round($max_v, 3) . ",
+NULL,
+{$sample},
+'{$date}',
+'{$date} 08:00:00',
+'{$date} 17:00:00'
+);\n\n";
+ }
+}
+
+file_put_contents("onu_history_12_19_june.sql", $sql);
+
+echo "DONE: file SQL berhasil dibuat";
\ No newline at end of file
diff --git a/api/get_onu_by_item.php b/api/get_onu_by_item.php
new file mode 100644
index 0000000..3da228c
--- /dev/null
+++ b/api/get_onu_by_item.php
@@ -0,0 +1,50 @@
+getConnection();
+
+$id = $_GET['id'] ?? null;
+
+if (!$id) {
+ echo json_encode(['success' => false, 'message' => 'ID kosong']);
+ exit;
+}
+
+// 1. ambil SN dari ftth_items
+$query = "SELECT sn_onu FROM ftth_items WHERE id = :id";
+$stmt = $db->prepare($query);
+$stmt->bindParam(':id', $id);
+$stmt->execute();
+
+$item = $stmt->fetch(PDO::FETCH_ASSOC);
+
+if (!$item || empty($item['sn_onu'])) {
+ echo json_encode(['success' => false, 'message' => 'SN tidak ada']);
+ exit;
+}
+
+// 2. ambil dari onu_status
+$query = "SELECT status, rx_power, last_update
+ FROM onu_status
+ WHERE sn = :sn
+ LIMIT 1";
+
+$stmt = $db->prepare($query);
+$stmt->bindParam(':sn', $item['sn_onu']);
+$stmt->execute();
+
+$data = $stmt->fetch(PDO::FETCH_ASSOC);
+
+if ($data) {
+ echo json_encode([
+ 'success' => true,
+ 'data' => $data
+ ]);
+} else {
+ echo json_encode([
+ 'success' => false,
+ 'message' => 'Data ONU tidak ditemukan'
+ ]);
+}
\ No newline at end of file
diff --git a/api/get_onu_volt.php b/api/get_onu_volt.php
new file mode 100644
index 0000000..2832056
--- /dev/null
+++ b/api/get_onu_volt.php
@@ -0,0 +1,105 @@
+getConnection();
+
+$item_id = intval($_GET['id'] ?? 0);
+
+if (!$item_id) {
+ echo json_encode([
+ 'success' => false,
+ 'message' => 'ID tidak valid'
+ ]);
+ exit;
+}
+
+/*
+|--------------------------------------------------------------------------
+| Ambil SN dari ftth_items
+|--------------------------------------------------------------------------
+*/
+
+$stmt = $conn->prepare("
+ SELECT sn_onu
+ FROM ftth_items
+ WHERE id = ?
+");
+
+$stmt->execute([$item_id]);
+
+$item = $stmt->fetch(PDO::FETCH_ASSOC);
+
+if (!$item || empty($item['sn_onu'])) {
+
+ echo json_encode([
+ 'success' => false,
+ 'message' => 'SN tidak ada'
+ ]);
+
+ exit;
+}
+
+$sn = trim($item['sn_onu']);
+
+/*
+|--------------------------------------------------------------------------
+| Ambil optical terakhir
+|--------------------------------------------------------------------------
+*/
+
+$stmt = $conn->prepare("
+ SELECT
+ sn,
+ ont_name,
+ rx_power,
+ voltage,
+ min_rx,
+ max_rx,
+ min_voltage,
+ max_voltage,
+ updated_at
+ FROM onu_daily_history
+ WHERE sn = ?
+ ORDER BY updated_at DESC
+ LIMIT 1
+");
+
+$stmt->execute([$sn]);
+
+$data = $stmt->fetch(PDO::FETCH_ASSOC);
+
+if (!$data) {
+
+ echo json_encode([
+ 'success' => false,
+ 'message' => 'Data optical tidak ditemukan'
+ ]);
+
+ exit;
+}
+
+/*
+|--------------------------------------------------------------------------
+| Format Data
+|--------------------------------------------------------------------------
+*/
+
+$data['rx_power'] = number_format((float)$data['rx_power'], 2) . ' dBm';
+
+$data['voltage'] = number_format((float)$data['voltage'], 2) . ' V';
+
+$data['min_rx'] = number_format((float)$data['min_rx'], 2) . ' dBm';
+
+$data['max_rx'] = number_format((float)$data['max_rx'], 2) . ' dBm';
+
+$data['min_voltage'] = number_format((float)$data['min_voltage'], 2) . ' V';
+
+$data['max_voltage'] = number_format((float)$data['max_voltage'], 2) . ' V';
+echo json_encode([
+ 'success' => true,
+ 'data' => $data
+]);
\ No newline at end of file
diff --git a/api/histori_onu.php b/api/histori_onu.php
new file mode 100644
index 0000000..1f0537c
--- /dev/null
+++ b/api/histori_onu.php
@@ -0,0 +1,42 @@
+getConnection();
+
+$id = $_GET['id'] ?? null;
+
+if (!$id) {
+ echo json_encode(['success' => false]);
+ exit;
+}
+
+// ambil SN dari item
+$stmt = $conn->prepare("SELECT sn_onu FROM ftth_items WHERE id = ?");
+$stmt->execute([$id]);
+$item = $stmt->fetch(PDO::FETCH_ASSOC);
+
+if (!$item) {
+ echo json_encode(['success' => false]);
+ exit;
+}
+
+$sn = $item['sn_onu'];
+
+// ambil histori anomali saja
+$stmt = $conn->prepare("
+ SELECT *
+ FROM status_onu_histori
+ WHERE sn = ?
+ ORDER BY created_at DESC
+ LIMIT 100
+");
+
+$stmt->execute([$sn]);
+$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
+
+echo json_encode([
+ 'success' => true,
+ 'sn' => $sn,
+ 'data' => $data
+]);
\ No newline at end of file
diff --git a/api/histori_redaman.php b/api/histori_redaman.php
new file mode 100644
index 0000000..27e7439
--- /dev/null
+++ b/api/histori_redaman.php
@@ -0,0 +1,94 @@
+getConnection();
+
+$item_id = intval($_GET['id'] ?? 0);
+
+if (!$item_id) {
+ echo json_encode([
+ 'success' => false,
+ 'message' => 'ID tidak valid'
+ ]);
+ exit;
+}
+
+/*
+|--------------------------------------------------------------------------
+| Ambil SN dari ftth_items
+|--------------------------------------------------------------------------
+*/
+$stmt = $conn->prepare("
+ SELECT sn_onu, name
+ FROM ftth_items
+ WHERE id = ?
+");
+$stmt->execute([$item_id]);
+$item = $stmt->fetch(PDO::FETCH_ASSOC);
+
+if (!$item || empty($item['sn_onu'])) {
+ echo json_encode([
+ 'success' => false,
+ 'message' => 'SN tidak ditemukan'
+ ]);
+ exit;
+}
+
+$sn = trim($item['sn_onu']);
+
+/*
+|--------------------------------------------------------------------------
+| Ambil histori redaman & voltage
+|--------------------------------------------------------------------------
+*/
+$stmt = $conn->prepare("
+ SELECT
+ rx_power,
+ voltage,
+ updated_at
+ FROM onu_daily_history
+ WHERE sn = ?
+ ORDER BY updated_at DESC
+ LIMIT 30
+");
+
+$stmt->execute([$sn]);
+$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
+
+if (!$data) {
+ echo json_encode([
+ 'success' => false,
+ 'message' => 'Histori kosong'
+ ]);
+ exit;
+}
+
+/*
+|--------------------------------------------------------------------------
+| Format biar rapi (opsional)
+|--------------------------------------------------------------------------
+*/
+foreach ($data as &$row) {
+
+ // format RX
+ if ($row['rx_power'] !== null) {
+ $row['rx_power'] = number_format((float)$row['rx_power'], 2) . ' dBm';
+ }
+
+ // format voltage
+ if ($row['voltage'] !== null) {
+ $row['voltage'] = number_format((float)$row['voltage'], 2) . ' V';
+ }
+
+ // tanggal lebih enak dibaca
+ $row['updated_at'] = date('d-m-Y H:i:s', strtotime($row['updated_at']));
+}
+
+echo json_encode([
+ 'success' => true,
+ 'sn' => $sn,
+ 'data' => $data
+]);
\ No newline at end of file
diff --git a/api/items.php b/api/items.php
index 37053ad..6316dc6 100644
--- a/api/items.php
+++ b/api/items.php
@@ -11,81 +11,65 @@ if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
exit();
}
+session_start(); // <-- Tambahan penting
+
require_once __DIR__ . '/../config/database.php';
+// Ambil user info dari session
+$user_id = $_SESSION['user_id'] ?? null;
+$role = $_SESSION['role'] ?? 'teknisi1';
+
// Function to manually parse multipart form data
function parseMultipartFormData($input, $contentType) {
$data = array();
-
- // Extract boundary from content type
if (preg_match('/boundary=(.+)$/', $contentType, $matches)) {
$boundary = $matches[1];
-
- // Split the input by boundary
$parts = array_slice(explode('--' . $boundary, $input), 1);
-
foreach ($parts as $part) {
- // Skip empty parts and closing boundary
if (trim($part) == '--' || empty(trim($part))) continue;
-
- // Split headers and body
$sections = explode("\r\n\r\n", $part, 2);
if (count($sections) != 2) continue;
-
$headers = $sections[0];
$body = rtrim($sections[1], "\r\n");
-
- // Extract field name from Content-Disposition header
if (preg_match('/name="([^"]*)"/', $headers, $matches)) {
$fieldName = $matches[1];
$data[$fieldName] = $body;
}
}
}
-
return $data;
}
$database = new Database();
$db = $database->getConnection();
-// Handle method override and multipart data parsing
$method = $_SERVER['REQUEST_METHOD'];
$parsed_data = array();
-// Parse multipart form data manually if needed
if (($method === 'PUT' || $method === 'PATCH') && empty($_POST) &&
isset($_SERVER['CONTENT_TYPE']) && strpos($_SERVER['CONTENT_TYPE'], 'multipart/form-data') !== false) {
-
- // Force treat as POST to get parsed form data
$raw_input = file_get_contents('php://input');
$parsed_data = parseMultipartFormData($raw_input, $_SERVER['CONTENT_TYPE']);
-
- // If we found form data, treat this as a method override
if (!empty($parsed_data)) {
if (isset($parsed_data['_method'])) {
$method = strtoupper($parsed_data['_method']);
unset($parsed_data['_method']);
}
- // Populate $_POST with parsed data for compatibility
$_POST = $parsed_data;
}
}
-// Check for X-HTTP-Method-Override header
if (isset($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'])) {
$method = $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'];
}
-// Check for _method parameter (Laravel style) - now works with manually parsed data too
if (isset($_POST['_method'])) {
$method = strtoupper($_POST['_method']);
- unset($_POST['_method']); // Clean it up
+ unset($_POST['_method']);
}
$response = array('success' => false, 'message' => '', 'data' => null);
-// Log only important requests for production
if ($method === 'PUT' || $method === 'DELETE') {
error_log("FTTH API - " . $method . " request, ID: " . (isset($_POST['id']) ? $_POST['id'] : 'N/A'));
}
@@ -94,24 +78,30 @@ try {
switch($method) {
case 'GET':
if (isset($_GET['id'])) {
- // Get single item
$query = "SELECT i.*, i.serial_number,
- it.name as item_type_name, it.icon, it.color,
- tc.color_name as tube_color_name, tc.hex_code,
- cc.color_name as core_color_name, cc.hex_code as core_hex_code,
- sm.ratio as splitter_main_ratio,
- so.ratio as splitter_odp_ratio
- FROM ftth_items i
- LEFT JOIN item_types it ON i.item_type_id = it.id
- LEFT JOIN tube_colors tc ON i.tube_color_id = tc.id
- LEFT JOIN tube_colors cc ON i.core_color_id = cc.id
- LEFT JOIN splitter_types sm ON i.splitter_main_id = sm.id
- LEFT JOIN splitter_types so ON i.splitter_odp_id = so.id
- WHERE i.id = :id";
+ it.name as item_type_name, it.icon, it.color,
+ tc.color_name as tube_color_name, tc.hex_code,
+ cc.color_name as core_color_name, cc.hex_code as core_hex_code,
+ sm.ratio as splitter_main_ratio,
+ so.ratio as splitter_odp_ratio
+ FROM ftth_items i
+ LEFT JOIN item_types it ON i.item_type_id = it.id
+ LEFT JOIN tube_colors tc ON i.tube_color_id = tc.id
+ LEFT JOIN tube_colors cc ON i.core_color_id = cc.id
+ LEFT JOIN splitter_types sm ON i.splitter_main_id = sm.id
+ LEFT JOIN splitter_types so ON i.splitter_odp_id = so.id
+ WHERE i.id = :id";
+
+ // kalau teknisi, batasi ke user_id
+ if ($role !== 'engineer') {
+ $query .= " AND i.user_id = :user_id";
+ }
-
$stmt = $db->prepare($query);
$stmt->bindParam(':id', $_GET['id']);
+ if ($role !== 'engineer') {
+ $stmt->bindParam(':user_id', $user_id);
+ }
$stmt->execute();
$item = $stmt->fetch(PDO::FETCH_ASSOC);
@@ -122,23 +112,28 @@ try {
$response['message'] = 'Item not found';
}
} else {
- // Get all items
$query = "SELECT i.*, i.serial_number,
- it.name as item_type_name, it.icon, it.color,
- tc.color_name as tube_color_name, tc.hex_code,
- cc.color_name as core_color_name, cc.hex_code as core_hex_code,
- sm.ratio as splitter_main_ratio,
- so.ratio as splitter_odp_ratio
- FROM ftth_items i
- LEFT JOIN item_types it ON i.item_type_id = it.id
- LEFT JOIN tube_colors tc ON i.tube_color_id = tc.id
- LEFT JOIN tube_colors cc ON i.core_color_id = cc.id
- LEFT JOIN splitter_types sm ON i.splitter_main_id = sm.id
- LEFT JOIN splitter_types so ON i.splitter_odp_id = so.id
- ORDER BY i.created_at DESC";
+ it.name as item_type_name, it.icon, it.color,
+ tc.color_name as tube_color_name, tc.hex_code,
+ cc.color_name as core_color_name, cc.hex_code as core_hex_code,
+ sm.ratio as splitter_main_ratio,
+ so.ratio as splitter_odp_ratio
+ FROM ftth_items i
+ LEFT JOIN item_types it ON i.item_type_id = it.id
+ LEFT JOIN tube_colors tc ON i.tube_color_id = tc.id
+ LEFT JOIN tube_colors cc ON i.core_color_id = cc.id
+ LEFT JOIN splitter_types sm ON i.splitter_main_id = sm.id
+ LEFT JOIN splitter_types so ON i.splitter_odp_id = so.id";
+
+ if ($role !== 'engineer') {
+ $query .= " WHERE i.user_id = :user_id";
+ }
+ $query .= " ORDER BY i.created_at DESC";
-
$stmt = $db->prepare($query);
+ if ($role !== 'engineer') {
+ $stmt->bindParam(':user_id', $user_id);
+ }
$stmt->execute();
$items = $stmt->fetchAll(PDO::FETCH_ASSOC);
@@ -148,81 +143,91 @@ try {
break;
case 'POST':
- // Create new item
- $item_type_id = $_POST['item_type'] ?? null;
- $name = $_POST['name'] ?? null;
- $description = $_POST['description'] ?? null;
- $latitude = $_POST['latitude'] ?? null;
- $longitude = $_POST['longitude'] ?? null;
- $address = $_POST['address'] ?? null;
- $serial_number = $_POST['serial_number'] ?? null; // <--- Tambahan
-
- // Handle foreign key fields - convert empty strings to NULL
- $tube_color_id = (!empty($_POST['tube_color_id']) && $_POST['tube_color_id'] !== '0') ? $_POST['tube_color_id'] : null;
- $core_used = (!empty($_POST['core_used']) && $_POST['core_used'] !== '0') ? $_POST['core_used'] : null;
- $core_color_id = (!empty($_POST['core_color_id']) && $_POST['core_color_id'] !== '0') ? $_POST['core_color_id'] : null;
- $item_cable_type = $_POST['item_cable_type'] ?? 'distribution';
- $total_core_capacity = $_POST['total_core_capacity'] ?? 24;
- $splitter_main_id = (!empty($_POST['splitter_main_id']) && $_POST['splitter_main_id'] !== '0') ? $_POST['splitter_main_id'] : null;
- $splitter_odp_id = (!empty($_POST['splitter_odp_id']) && $_POST['splitter_odp_id'] !== '0') ? $_POST['splitter_odp_id'] : null;
- $status = $_POST['status'] ?? 'active';
-
- if (!$item_type_id || !$name || !$latitude || !$longitude) {
- $response['message'] = 'Required fields missing';
- break;
- }
-
- $query = "INSERT INTO ftth_items (
- item_type_id, name, description, latitude, longitude, address, serial_number,
- tube_color_id, core_used, core_color_id, item_cable_type, total_core_capacity,
- splitter_main_id, splitter_odp_id, status
- ) VALUES (
- :item_type_id, :name, :description, :latitude, :longitude, :address, :serial_number,
- :tube_color_id, :core_used, :core_color_id, :item_cable_type, :total_core_capacity,
- :splitter_main_id, :splitter_odp_id, :status
- )";
-
- $stmt = $db->prepare($query);
- $stmt->bindParam(':item_type_id', $item_type_id);
- $stmt->bindParam(':name', $name);
- $stmt->bindParam(':description', $description);
- $stmt->bindParam(':latitude', $latitude);
- $stmt->bindParam(':longitude', $longitude);
- $stmt->bindParam(':address', $address);
- $stmt->bindParam(':serial_number', $serial_number); // <--- Bind
- $stmt->bindParam(':tube_color_id', $tube_color_id);
- $stmt->bindParam(':core_used', $core_used);
- $stmt->bindParam(':core_color_id', $core_color_id);
- $stmt->bindParam(':item_cable_type', $item_cable_type);
- $stmt->bindParam(':total_core_capacity', $total_core_capacity);
- $stmt->bindParam(':splitter_main_id', $splitter_main_id);
- $stmt->bindParam(':splitter_odp_id', $splitter_odp_id);
- $stmt->bindParam(':status', $status);
+ $item_type_id = $_POST['item_type'] ?? null;
+ $name = $_POST['name'] ?? null;
+ $description = $_POST['description'] ?? null;
+ $latitude = $_POST['latitude'] ?? null;
+ $longitude = $_POST['longitude'] ?? null;
+ $address = $_POST['address'] ?? null;
+ $serial_number = $_POST['serial_number'] ?? null;
+ $sn_onu = $_POST['sn_onu'] ?? null;
+ $customer_phone = $_POST['customer_phone'] ?? null;
+ $tube_color_id = (!empty($_POST['tube_color_id']) && $_POST['tube_color_id'] !== '0') ? $_POST['tube_color_id'] : null;
+ $core_used = (!empty($_POST['core_used']) && $_POST['core_used'] !== '0') ? $_POST['core_used'] : null;
+ $core_color_id = (!empty($_POST['core_color_id']) && $_POST['core_color_id'] !== '0') ? $_POST['core_color_id'] : null;
+ $item_cable_type = (!empty($_POST['item_cable_type'])) ? $_POST['item_cable_type'] : null;
+ $total_core_capacity = $_POST['total_core_capacity'] ?? 24;
+ $splitter_main_id = (!empty($_POST['splitter_main_id']) && $_POST['splitter_main_id'] !== '0') ? $_POST['splitter_main_id'] : null;
+ $splitter_odp_id = (!empty($_POST['splitter_odp_id']) && $_POST['splitter_odp_id'] !== '0') ? $_POST['splitter_odp_id'] : null;
+ $status = $_POST['status'] ?? 'active';
+ if (!$item_type_id || !$name || !$latitude || !$longitude) {
+ $response['message'] = 'Required fields missing';
+ break;
+ }
+
+ if ($role === 'engineer') {
+ $query = "INSERT INTO ftth_items (
+ item_type_id, name, description, latitude, longitude, address, serial_number, sn_onu, customer_phone,
+ tube_color_id, core_used, core_color_id, item_cable_type, total_core_capacity,
+ splitter_main_id, splitter_odp_id, status
+ ) VALUES (
+ :item_type_id, :name, :description, :latitude, :longitude, :address, :serial_number, :sn_onu, :customer_phone,
+ :tube_color_id, :core_used, :core_color_id, :item_cable_type, :total_core_capacity,
+ :splitter_main_id, :splitter_odp_id, :status
+ )";
+ $stmt = $db->prepare($query);
+ } else {
+ $query = "INSERT INTO ftth_items (
+ user_id, item_type_id, name, description, latitude, longitude, address, serial_number, sn_onu, customer_phone,
+ tube_color_id, core_used, core_color_id, item_cable_type, total_core_capacity,
+ splitter_main_id, splitter_odp_id, status
+ ) VALUES (
+ :user_id, :item_type_id, :name, :description, :latitude, :longitude, :address, :serial_number, :sn_onu, :customer_phone,
+ :tube_color_id, :core_used, :core_color_id, :item_cable_type, :total_core_capacity,
+ :splitter_main_id, :splitter_odp_id, :status
+ )";
+ $stmt = $db->prepare($query);
+ $stmt->bindParam(':user_id', $user_id);
+ }
+
+ $stmt->bindParam(':item_type_id', $item_type_id);
+ $stmt->bindParam(':name', $name);
+ $stmt->bindParam(':description', $description);
+ $stmt->bindParam(':latitude', $latitude);
+ $stmt->bindParam(':longitude', $longitude);
+ $stmt->bindParam(':address', $address);
+ $stmt->bindParam(':serial_number', $serial_number);
+ $stmt->bindParam(':tube_color_id', $tube_color_id);
+ $stmt->bindParam(':core_used', $core_used);
+ $stmt->bindParam(':core_color_id', $core_color_id);
+ $stmt->bindParam(':item_cable_type', $item_cable_type);
+ $stmt->bindParam(':total_core_capacity', $total_core_capacity);
+ $stmt->bindParam(':splitter_main_id', $splitter_main_id);
+ $stmt->bindParam(':splitter_odp_id', $splitter_odp_id);
+ $stmt->bindParam(':status', $status);
+ $stmt->bindParam(':sn_onu', $sn_onu);
+ $stmt->bindParam(':customer_phone', $customer_phone);
+
if ($stmt->execute()) {
$item_id = $db->lastInsertId();
-
- // Get the created item with joins
$query = "SELECT i.*, i.serial_number,
- it.name as item_type_name, it.icon, it.color,
- tc.color_name as tube_color_name, tc.hex_code,
- cc.color_name as core_color_name, cc.hex_code as core_hex_code,
- sm.ratio as splitter_main_ratio,
- so.ratio as splitter_odp_ratio
- FROM ftth_items i
- LEFT JOIN item_types it ON i.item_type_id = it.id
- LEFT JOIN tube_colors tc ON i.tube_color_id = tc.id
- LEFT JOIN tube_colors cc ON i.core_color_id = cc.id
- LEFT JOIN splitter_types sm ON i.splitter_main_id = sm.id
- LEFT JOIN splitter_types so ON i.splitter_odp_id = so.id
- WHERE i.id = :id";
-
-
+ it.name as item_type_name, it.icon, it.color,
+ tc.color_name as tube_color_name, tc.hex_code,
+ cc.color_name as core_color_name, cc.hex_code as core_hex_code,
+ sm.ratio as splitter_main_ratio,
+ so.ratio as splitter_odp_ratio
+ FROM ftth_items i
+ LEFT JOIN item_types it ON i.item_type_id = it.id
+ LEFT JOIN tube_colors tc ON i.tube_color_id = tc.id
+ LEFT JOIN tube_colors cc ON i.core_color_id = cc.id
+ LEFT JOIN splitter_types sm ON i.splitter_main_id = sm.id
+ LEFT JOIN splitter_types so ON i.splitter_odp_id = so.id
+ WHERE i.id = :id";
$stmt = $db->prepare($query);
$stmt->bindParam(':id', $item_id);
$stmt->execute();
-
$response['success'] = true;
$response['message'] = 'Item created successfully';
$response['data'] = $stmt->fetch(PDO::FETCH_ASSOC);
@@ -232,67 +237,53 @@ try {
break;
case 'PUT':
- // Update item - now $_POST should be properly populated
$put_data = $_POST;
-
$id = $put_data['id'] ?? null;
-
if (!$id) {
$response['message'] = 'ID required for update';
break;
}
-
- // Build dynamic update query
$update_fields = array();
$params = array(':id' => $id);
-
- $allowed_fields = ['item_type', 'name', 'description', 'latitude', 'longitude', 'address', 'serial_number','tube_color_id', 'core_used', 'core_color_id', 'item_cable_type', 'total_core_capacity', 'splitter_main_id', 'splitter_odp_id', 'status'];
-
+ $allowed_fields = ['item_type', 'name', 'description', 'latitude', 'longitude', 'address', 'serial_number','tube_color_id', 'core_used', 'core_color_id', 'item_cable_type', 'total_core_capacity', 'splitter_main_id', 'splitter_odp_id', 'sn_onu', 'customer_phone','status'];
foreach ($allowed_fields as $field) {
if (isset($put_data[$field])) {
$db_field = $field === 'item_type' ? 'item_type_id' : $field;
$update_fields[] = "$db_field = :$field";
-
- // Handle empty values for foreign key fields - convert to NULL
$value = $put_data[$field];
- if (in_array($field, ['tube_color_id', 'core_color_id', 'splitter_main_id', 'splitter_odp_id']) &&
- ($value === '' || $value === '0' || $value === 0)) {
+ if (in_array($field, ['tube_color_id', 'core_color_id', 'splitter_main_id', 'splitter_odp_id']) && ($value === '' || $value === '0' || $value === 0)) {
$value = null;
}
-
$params[":$field"] = $value;
}
}
-
if (empty($update_fields)) {
$response['message'] = 'No fields to update';
break;
}
-
$query = "UPDATE ftth_items SET " . implode(', ', $update_fields) . " WHERE id = :id";
-
+ if ($role !== 'engineer') {
+ $query .= " AND user_id = :user_id";
+ $params[':user_id'] = $user_id;
+ }
$stmt = $db->prepare($query);
-
if ($stmt->execute($params)) {
- // Get updated item
- $query = "SELECT i.*, i.serial_number,
- it.name as item_type_name, it.icon, it.color,
- tc.color_name as tube_color_name, tc.hex_code,
- cc.color_name as core_color_name, cc.hex_code as core_hex_code,
- sm.ratio as splitter_main_ratio,
- so.ratio as splitter_odp_ratio
- FROM ftth_items i
- LEFT JOIN item_types it ON i.item_type_id = it.id
- LEFT JOIN tube_colors tc ON i.tube_color_id = tc.id
- LEFT JOIN tube_colors cc ON i.core_color_id = cc.id
- LEFT JOIN splitter_types sm ON i.splitter_main_id = sm.id
- LEFT JOIN splitter_types so ON i.splitter_odp_id = so.id
- WHERE i.id = :id";
-
+ $query = "SELECT i.*, i.serial_number, i.sn_onu, i.customer_phone,
+ it.name as item_type_name, it.icon, it.color,
+ tc.color_name as tube_color_name, tc.hex_code,
+ cc.color_name as core_color_name, cc.hex_code as core_hex_code,
+ sm.ratio as splitter_main_ratio,
+ so.ratio as splitter_odp_ratio
+ FROM ftth_items i
+ LEFT JOIN item_types it ON i.item_type_id = it.id
+ LEFT JOIN tube_colors tc ON i.tube_color_id = tc.id
+ LEFT JOIN tube_colors cc ON i.core_color_id = cc.id
+ LEFT JOIN splitter_types sm ON i.splitter_main_id = sm.id
+ LEFT JOIN splitter_types so ON i.splitter_odp_id = so.id
+ WHERE i.id = :id";
$stmt = $db->prepare($query);
$stmt->bindParam(':id', $id);
$stmt->execute();
-
$response['success'] = true;
$response['message'] = 'Item updated successfully';
$response['data'] = $stmt->fetch(PDO::FETCH_ASSOC);
@@ -302,41 +293,35 @@ try {
break;
case 'DELETE':
- // Delete item
$input = file_get_contents("php://input");
$delete_data = array();
-
- // Try to parse JSON first, then form data
$json_data = json_decode($input, true);
if ($json_data) {
$delete_data = $json_data;
} else {
parse_str($input, $delete_data);
}
-
- // Also check for regular POST data (for compatibility)
if (empty($delete_data)) {
$delete_data = $_POST;
}
-
$id = $delete_data['id'] ?? null;
-
if (!$id) {
$response['message'] = 'ID required for deletion';
break;
}
-
- // Delete related routes first
$query = "DELETE FROM cable_routes WHERE from_item_id = :id OR to_item_id = :id";
$stmt = $db->prepare($query);
$stmt->bindParam(':id', $id);
$stmt->execute();
-
- // Delete the item
$query = "DELETE FROM ftth_items WHERE id = :id";
+ if ($role !== 'engineer') {
+ $query .= " AND user_id = :user_id";
+ }
$stmt = $db->prepare($query);
$stmt->bindParam(':id', $id);
-
+ if ($role !== 'engineer') {
+ $stmt->bindParam(':user_id', $user_id);
+ }
if ($stmt->execute()) {
$response['success'] = true;
$response['message'] = 'Item deleted successfully';
@@ -355,4 +340,4 @@ try {
}
echo json_encode($response);
-?>
\ No newline at end of file
+?>
diff --git a/api/laporan_odp.php b/api/laporan_odp.php
new file mode 100644
index 0000000..c39a6d8
--- /dev/null
+++ b/api/laporan_odp.php
@@ -0,0 +1,314 @@
+getConnection();
+
+
+if (isset($_GET['kirim']) && isset($_GET['id'])) {
+
+ function kirimWA($pesan) {
+ $token = "XjC9oSr4jECWG93JQRWf";
+
+ $data = [
+ "target" => "120363407747513164@g.us",
+ "message" => $pesan,
+ ];
+
+ $curl = curl_init();
+
+ curl_setopt_array($curl, [
+ CURLOPT_URL => "https://api.fonnte.com/send",
+ CURLOPT_RETURNTRANSFER => true,
+ CURLOPT_POST => true,
+ CURLOPT_POSTFIELDS => http_build_query($data),
+ CURLOPT_HTTPHEADER => [
+ "Authorization: $token"
+ ],
+ ]);
+
+ curl_exec($curl);
+ curl_close($curl);
+ }
+
+ $id = $_GET['id'];
+
+ // 🔥 ambil ODP
+ $stmt = $conn->prepare("
+ SELECT i.id, i.name, i.latitude, i.longitude
+ FROM ftth_items i
+ WHERE i.id = ?
+ ");
+ $stmt->execute([$id]);
+ $odp = $stmt->fetch(PDO::FETCH_ASSOC);
+
+ if (!$odp) {
+ echo json_encode(['success' => false]);
+ exit;
+ }
+
+ // 🔥 ambil client
+ $stmtClient = $conn->prepare("
+ SELECT fi.id, fi.name, fi.serial_number
+ FROM cable_routes cr
+ JOIN ftth_items fi
+ ON (cr.to_item_id = fi.id OR cr.from_item_id = fi.id)
+ WHERE (cr.from_item_id = :id OR cr.to_item_id = :id)
+ AND fi.id != :id
+ ");
+ $stmtClient->bindParam(':id', $id);
+ $stmtClient->execute();
+
+ $clients = $stmtClient->fetchAll(PDO::FETCH_ASSOC);
+
+ $rxValues = [];
+ $clientBad = [];
+
+ foreach ($clients as $c) {
+
+ if (empty($c['serial_number'])) continue;
+
+ $query = json_encode(["_id" => $c['serial_number']]);
+ $url = "http://rmtstb.megadataisp.net:7557/devices/?query=" . urlencode($query);
+
+ $ch = curl_init();
+ curl_setopt($ch, CURLOPT_URL, $url);
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($ch, CURLOPT_TIMEOUT, 5);
+
+ $res = curl_exec($ch);
+ curl_close($ch);
+
+ if (!$res) continue;
+
+ $json = json_decode($res, true);
+
+ if (
+ isset($json[0]['VirtualParameters']['RXPower']['_value']) &&
+ is_numeric($json[0]['VirtualParameters']['RXPower']['_value'])
+ ) {
+ $rx = floatval($json[0]['VirtualParameters']['RXPower']['_value']);
+
+ $rxValues[] = $rx;
+
+ if ($rx < -23) {
+ $clientBad[] = $c['name'] . " (" . $rx . " dBm)";
+ }
+ }
+ }
+
+ // 🔥 HITUNG
+ $total = count($rxValues);
+ $bad = count($clientBad);
+ $good = $total - $bad;
+
+ $avg = $total > 0 ? round(array_sum($rxValues) / $total, 2) : '-';
+ $min = $total > 0 ? min($rxValues) : '-';
+
+ // 🔥 STATUS
+ $status = "BAIK";
+
+ if ($total == 0) {
+ $status = "NO DATA";
+ } elseif ($min < -27) {
+ $status = "KRITIS";
+ } elseif ($avg < -25 || $bad > ($total * 0.5)) {
+ $status = "BURUK";
+ } elseif ($avg < -23 || $bad > ($total * 0.3)) {
+ $status = "WARNING";
+ }
+
+ // 🔥 FORMAT WA
+ $maps = "https://www.google.com/maps?q={$odp['latitude']},{$odp['longitude']}";
+
+ $pesan = "🚨 *LAPORAN ODP*\n\n";
+ $pesan .= "📍 *ODP:* {$odp['name']}\n";
+ $pesan .= "📊 *Status:* {$status}\n\n";
+
+ $pesan .= "👥 *Total Client:* {$total}\n";
+ $pesan .= "🟢 Client Baik: {$good}\n";
+ $pesan .= "🔴 Client Buruk: {$bad}\n\n";
+
+ $pesan .= "📶 *AVG RX:* {$avg} dBm\n";
+ $pesan .= "📉 *MIN RX:* {$min} dBm\n\n";
+
+ if (!empty($clientBad)) {
+ $pesan .= "⚠ *Client Bermasalah:*\n";
+ $pesan .= implode("\n", array_slice($clientBad, 0, 10));
+ $pesan .= "\n\n";
+ }
+
+ $pesan .= "📌 Lokasi:\n$maps\n\n";
+ $pesan .= "🔎 Silakan cek detail di dashboard.";
+
+ kirimWA($pesan);
+
+ echo json_encode(['success' => true]);
+ exit;
+}
+
+// ✅ Ambil semua ODP
+$stmt = $conn->query("
+ SELECT i.id, i.name, i.latitude, i.longitude
+ FROM ftth_items i
+ LEFT JOIN item_types it ON i.item_type_id = it.id
+ WHERE LOWER(it.name) = 'odp'
+ AND i.user_id = 22
+");
+
+$odps = $stmt->fetchAll(PDO::FETCH_ASSOC);
+
+$result = [];
+
+foreach ($odps as $odp) {
+
+ // ✅ ambil client
+ $stmtClient = $conn->prepare("
+ SELECT fi.id, fi.name, fi.serial_number
+ FROM cable_routes cr
+ JOIN ftth_items fi
+ ON (cr.to_item_id = fi.id OR cr.from_item_id = fi.id)
+ WHERE (cr.from_item_id = :id OR cr.to_item_id = :id)
+ AND fi.id != :id
+ ");
+ $stmtClient->bindParam(':id', $odp['id']);
+ $stmtClient->execute();
+
+ $clients = $stmtClient->fetchAll(PDO::FETCH_ASSOC);
+
+ $rxValues = [];
+ $rxList = [];
+ $rxBadList = [];
+ $clientBad = [];
+
+ foreach ($clients as $c) {
+
+ if (empty($c['serial_number'])) continue;
+
+ $query = json_encode(["_id" => $c['serial_number']]);
+ $url = "http://rmtstb.megadataisp.net:7557/devices/?query=" . urlencode($query);
+
+ $ch = curl_init();
+ curl_setopt($ch, CURLOPT_URL, $url);
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($ch, CURLOPT_TIMEOUT, 5);
+
+ $res = curl_exec($ch);
+ curl_close($ch);
+
+ if (!$res) continue;
+
+ $json = json_decode($res, true);
+
+ if (
+ isset($json[0]['VirtualParameters']['RXPower']['_value']) &&
+ is_numeric($json[0]['VirtualParameters']['RXPower']['_value'])
+ ) {
+ $rx = floatval($json[0]['VirtualParameters']['RXPower']['_value']);
+
+ $rxValues[] = $rx;
+ $rxList[] = $rx;
+
+ if ($rx < -23) {
+ $rxBadList[] = $rx;
+ $clientBad[] = $c['name'] . " (" . $rx . " dBm)";
+ }
+ }
+ }
+
+ // 🔴 Tidak ada data
+ if (count($rxValues) == 0) {
+ $result[] = [
+ 'id' => $odp['id'],
+ 'nama' => $odp['name'],
+ 'lat' => $odp['latitude'],
+ 'lng' => $odp['longitude'],
+ 'total' => 0,
+ 'avg_rx' => null,
+ 'bad_count' => 0,
+ 'min_rx' => null,
+ 'status' => 'NO DATA',
+ 'status_color' => 'secondary',
+ 'analisa' => 'Tidak ada data pelanggan / ONU offline semua'
+ ];
+ continue;
+ }
+
+ $total = count($rxValues);
+ $avg = array_sum($rxValues) / $total;
+ $min = min($rxValues);
+
+ $bad = count($rxBadList);
+
+ // 🔥 DETEKSI SELISIH
+ $selisih = abs($avg - $min);
+
+ // 🔥 STATUS
+ $status = "BAIK";
+ $color = "success";
+
+ if ($selisih > 1.5) {
+ $status = "WARNING";
+ $color = "warning";
+ }
+
+ if ($avg < -23 || $bad > ($total * 0.3)) {
+ $status = "WARNING";
+ $color = "warning";
+ }
+
+ if ($avg < -25 || $bad > ($total * 0.5)) {
+ $status = "BURUK";
+ $color = "danger";
+ }
+
+ if ($min < -27) {
+ $status = "KRITIS";
+ $color = "dark";
+ }
+
+ // 🔥 ANALISA + TAMBAHAN INFORMASI CLIENT
+ if ($min < ($avg - 1.5)) {
+ $analisa = "Ada client lebih jelek dari yang lain → kemungkinan IKR/dropcore bermasalah";
+ }
+ elseif ($status === "KRITIS") {
+ $analisa = "Banyak RX < -27 dBm → kemungkinan feeder/ODP bermasalah";
+ }
+ elseif ($status === "BURUK") {
+ $analisa = "Lebih dari 50% client jelek → indikasi splitter ODP / konektor kotor";
+ }
+ elseif ($status === "WARNING") {
+ $analisa = "Sebagian client jelek → kemungkinan jalur ke rumah";
+ }
+ else {
+ $analisa = "Semua pelanggan normal";
+ }
+
+ // 🔥 TAMBAHKAN DETAIL RX & CLIENT BURUK KE ANALISA
+ $analisa .= " | RX: " . implode(", ", $rxList);
+
+ if (!empty($clientBad)) {
+ $analisa .= " | Client bermasalah: " . implode(", ", $clientBad);
+ }
+
+ $result[] = [
+ 'id' => $odp['id'],
+ 'nama' => $odp['name'],
+ 'lat' => $odp['latitude'],
+ 'lng' => $odp['longitude'],
+ 'total' => $total,
+ 'avg_rx' => round($avg, 2),
+ 'bad_count' => $bad,
+ 'min_rx' => $min,
+ 'status' => $status,
+ 'status_color' => $color,
+ 'analisa' => $analisa
+ ];
+}
+
+echo json_encode([
+ 'success' => true,
+ 'data' => $result
+]);
\ No newline at end of file
diff --git a/api/log.php b/api/log.php
new file mode 100644
index 0000000..07d670b
--- /dev/null
+++ b/api/log.php
@@ -0,0 +1,167 @@
+getConnection();
+
+$login_url = "http://10.255.254.21/login";
+$cookie = __DIR__ . "/cookie.txt";
+
+/*
+|--------------------------------------------------------------------------
+| LOGIN
+|--------------------------------------------------------------------------
+*/
+$ch = curl_init();
+
+curl_setopt_array($ch, [
+ CURLOPT_URL => $login_url,
+ CURLOPT_POST => true,
+ CURLOPT_POSTFIELDS => http_build_query([
+ "username" => "root",
+ "password" => "@lokal234"
+ ]),
+ CURLOPT_RETURNTRANSFER => true,
+ CURLOPT_COOKIEJAR => $cookie,
+ CURLOPT_COOKIEFILE => $cookie,
+]);
+
+$login = curl_exec($ch);
+
+echo "| Nama ODP | +Total Client | +AVG RX | +Client Buruk | +Status | +Map | +Notif | +
|---|---|---|---|---|---|---|
|
+ ${item.nama} + + + ${item.analisa.split('|')[0]} + + + ${rxText ? ` RX: ${rxText}` : ''} + + ${badClientText ? ` + + ⚠ ${badClientText} + ` : ''} + |
+
+ ${item.total} | + +${item.avg_rx ?? '-'} dBm | + +${item.bad_count} | + ++ + ${item.status} + + | + ++ + + | + + ++ + | + +
| Jenis | @@ -408,11 +552,23 @@ function generateItemListHtml(items) {
|---|
| Dari | @@ -504,11 +663,23 @@ function generateRouteListHtml(routes) {
|---|
| No | +Waktu | +Status | +RX Power | +
|---|
| No | +Waktu | +RX Power | +Voltage | +
|---|
Jarak: ${(distance / 1000).toFixed(2)} km
+Tipe Kabel: Fiber Optic
+Jumlah Core: 24
+Status: Perencanaan
+Status: ${getStatusText(route.status)}
Routing Kabel
+Laporan ODP
+ +Tambah Pelanggan