Publikasi
Server STB & Arsitektur Sistem JARPAK
Arsitektur edge server STB: go2rtc streaming, record.py API, nginx, autentikasi, Cloudflare Tunnel, dan alur data.
# Arsitektur & Alur Sistem JARPAK
Lokasi: Pos Ronda Karanggeneng
Edge device: STB Amlogic S9xx (aml-s9xx-box, Armbian)
Domain publik: bagaswara.hibahkaranggeneng.site
Disusun: 28 Oktober 2026, 23.16 WIB
Sifat dokumen: deskripsi arsitektur + alur dalam teks, siap dipakai untuk menggambar flowchart.
Dokumen ini menjelaskan kondisi apa adanya (as-built), termasuk bagian yang masih bermasalah. Bagian yang perlu diverifikasi ditandai [VERIFIKASI].
1. Ringkasan Eksekutif
JARPAK adalah sistem monitoring lingkungan pos ronda yang terdiri dari:
- Sensor & aktuator lapangan — ESP32 membaca PLN, aki, inverter, UPS, suhu, dan mengendalikan sirene.
- Kamera — 2 kamera IP terhubung ke NVR, di-stream ulang oleh go2rtc di STB.
- STB sebagai edge server — menjalankan web server, API telemetri, gateway stream, autentikasi, Cloudflare Tunnel, Tailscale, dan kiosk HDMI.
- Tampilan — kiosk TV 1080p, dashboard web publik, dan aplikasi Android.
Inti arsitekturnya: STB adalah satu-satunya simpul yang menyatukan data lapangan, stream kamera, dan tampilan publik. Tidak ada cloud database; semua data operasional disimpan lokal di SQLite dan file di SD card.
Status ringkas saat dokumen disusun:
- Layanan inti (go2rtc, record.py, nginx, auth, tunnel, Tailscale) aktif.
- Kiosk HDMI mati karena HDMI terdeteksi
disconnected;kiosk.serviceberstatusfailed. - Overlay ticker ikut mati karena hanya dijalankan oleh
kiosk.sh. - NVR
192.168.0.20tidak terjangkau dari STB (beda subnet), sehingga live view kamera mati. - Link serial ESP32 tidak terdeteksi; nilai telemetri perangkat saat ini berasal dari simulator fallback di
record.py, bukan sensor nyata. - Perekaman lokal dimatikan (
ENABLE_RECORDING=0); rekaman sepenuhnya di NVR. - Backup harian dan health check berjalan.
2. Prinsip & Batasan Desain
- Output kiosk wajib 1080p ke HDMI, tidak boleh 4K, full screen tanpa scroll.
- Aplikasi Bagaswara read-only — perubahan aplikasi hanya boleh lewat
D:\BRIEF-APLIKASI-BAGASWARA.md. - STB menjadi edge tunggal — tidak ada server cloud terpisah; internet hanya untuk akses publik dan remote.
- Data operasional tetap lokal — SQLite + SD card; cloud hanya jalur akses.
- Kiosk harus tetap tampil walau internet mati — dashboard kiosk dilayani dari
127.0.0.1:1985. - Keamanan akses publik — dashboard di balik login; API internal sebisa mungkin tidak terekspos langsung.
3. Arsitektur Berlapis
+------------------------------------------------------------------+
| LAPISAN 1 - FISIK / LAPANGAN |
| PLN - Aki 12V - Inverter - UPS - ESP32 (sensor + sirene) |
| NVR 192.168.0.20 - 2 kamera IP |
| TV HDMI 1080p - Router/AP 192.168.1.1 |
+----------------------------------+-------------------------------+
| serial / RTSP / HDMI / Ethernet
+----------------------------------v-------------------------------+
| LAPISAN 2 - EDGE STB (Armbian, systemd) |
| go2rtc (stream) | record.py (API + DB) | nginx (web) |
| jarpak-auth (login) | cloudflared (tunnel) | tailscaled |
| NetworkManager (eth/WiFi failover) | kiosk + overlay ticker |
| kiosk-hdmi-poll | stb-health | cctv-backup | chrony |
+----------------------------------+-------------------------------+
| baca/tulis
+----------------------------------v-------------------------------+
| LAPISAN 3 - DATA |
| SQLite /opt/camera/data.db |
| File rekaman /mnt/sdcard/cctv (nonaktif) |
| Backup /mnt/sdcard/backup/*.tar.gz |
| Health log /mnt/sdcard/health/YYYY-MM-DD.log |
+----------------------------------+-------------------------------+
| HTTP / WebSocket / HLS
+----------------------------------v-------------------------------+
| LAPISAN 4 - PRESENTASI |
| Kiosk Chromium 1080p + window overlay ticker 60fps |
| Website publik + dashboard (login) |
| Aplikasi Android |
+----------------------------------+-------------------------------+
| internet
+----------------------------------v-------------------------------+
| LAPISAN 5 - EKSTERNAL |
| Cloudflare Tunnel + CDN | Tailscale | NTP | Internet |
+------------------------------------------------------------------+
Penjelasan tiap lapisan
- Fisik/lapangan: sumber data dan aktuator. ESP32 adalah satu-satunya jalur telemetri dan sirene. NVR adalah sumber stream kamera.
- Edge STB: seluruh logika sistem. Tidak ada dependensi ke server lain selain NVR dan internet.
- Data: SQLite menjadi sumber kebenaran konfigurasi kamera dan ticker;
go2rtc.yamladalah cermin dari tabelcameras. - Presentasi: kiosk memakai jalur lokal (
127.0.0.1) agar tidak bergantung internet; web publik memakai tunnel. - Eksternal: Cloudflare untuk akses publik, Tailscale untuk remote SSH, NTP untuk waktu.
4. Topologi Jaringan
INTERNET
|
+---------+---------+
| Cloudflare Tunnel |
| (cloudflared) |
+---------+---------+
| outbound QUIC
+---------------------------v-----------------------------+
| Router/AP 192.168.1.1 |
| +- STB aml-s9xx-box eth0 192.168.1.11/24 |
| | +- Tailscale 100.77.104.5 |
| +- TV HDMI (langsung ke STB) |
| +- Perangkat lain di LAN 192.168.1.0/24 |
| |
| NVR 192.168.0.20 -> BEDA SUBNET, TIDAK ADA ROUTE |
| +- CAM 1 (channel 1) |
| +- CAM 2 (channel 2) |
+---------------------------------------------------------+
Fakta jaringan saat ini:
eth0UP,192.168.1.11/24, gateway192.168.1.1.wlan0/wlan1DOWN (mode ethernet-first).- Tailscale
100.77.104.5aktif; akses SSH remote lewat Tailscale. - NVR
192.168.0.20tidak punya rute dari192.168.1.11; ping/RTSP gagal. - Publik lewat Cloudflare Tunnel; tidak ada port forwarding di router.
Implikasi: live view kamera hanya bisa hidup jika NVR bisa dijangkau. Pilihan perbaikan: pindahkan NVR ke subnet 192.168.1.0/24, tambahkan rute statis/VLAN, atau pasang NVR di switch yang sama.
5. Komponen & Tanggung Jawab
| Komponen | Proses / Service | User | Bind | Tanggung jawab | Status |
|---|---|---|---|---|---|
| go2rtc | camera.service |
cctv |
127.0.0.1:1985, *:8555, *:8556 |
Stream RTSP NVR → WebRTC/HLS/MP4; serve static /opt/camera/www |
aktif |
| record.py | camera-record.service |
cctv + dialout |
127.0.0.1:8088 |
API telemetri, ticker, sirene, kamera, settings; SQLite; simulator; promoter | aktif |
| nginx | nginx.service |
www-data |
0.0.0.0:1984 |
Web publik, reverse proxy /api/ ke go2rtc, auth_request |
aktif |
| jarpak-auth | jarpak-auth.service |
www-data |
127.0.0.1:8099 |
Login, cookie HMAC, rate limit | aktif |
| cloudflared | cloudflared.service |
root | outbound | Tunnel publik ke nginx/API | aktif |
| tailscaled | tailscaled.service |
root | tailscale0 |
Remote SSH/akses privat | aktif |
| NetworkManager | NetworkManager + dispatcher |
root | — | Ethernet-first, WiFi failover | aktif |
| kiosk | kiosk.service |
root | :0 |
Xorg + Chromium fullscreen 1080p | failed (HDMI putus) |
| overlay ticker | child dari kiosk.sh |
root | 9223 |
Chromium window 1920×68, ticker 60fps | mati (ikut kiosk) |
| kiosk-hdmi-poll | kiosk-hdmi-poll.timer |
root | — | Start/stop kiosk sesuai status HDMI | timer aktif |
| stb-health | cron /etc/crontab tiap 10 menit |
root | — | Log kesehatan STB | aktif |
| cctv-backup | cron root 03.30 | root | — | Backup tar.gz harian | aktif |
| chrony | chrony.service |
root | 323/udp | Sinkronisasi waktu | aktif |
| ESP32 | firmware eksternal | — | serial | Baca sensor, kontrol sirene | tidak terdeteksi |
| NVR | perangkat eksternal | — | 192.168.0.20:554 |
Rekaman + sumber RTSP | tidak terjangkau |
6. Port & Endpoint
6.1 Port
| Port | Protokol | Bind | Fungsi | Akses |
|---|---|---|---|---|
| 22 | TCP | semua | SSH | LAN/Tailscale |
| 1984 | HTTP | 0.0.0.0 |
Website + dashboard + proxy | LAN & tunnel |
| 1985 | HTTP | 127.0.0.1 |
go2rtc API + static + WebSocket | lokal |
| 8088 | HTTP | 127.0.0.1 |
API record.py | lokal |
| 8099 | HTTP | 127.0.0.1 |
Auth service | lokal (via nginx) |
| 8555 | RTSP | semua | go2rtc RTSP | LAN |
| 8556 | WebRTC | semua | go2rtc WebRTC | LAN/tunnel |
| 9222 | CDP | 127.0.0.1 |
Debug Chromium kiosk | lokal |
| 9223 | CDP | 127.0.0.1 |
Debug Chromium overlay | lokal |
| 41641 | UDP | — | Tailscale | internet |
| 323 | UDP | — | NTP/chrony | internet |
6.2 Endpoint record.py (:8088)
| Method | Path | Fungsi | Auth |
|---|---|---|---|
| GET | /api/telemetry |
Nilai terbaru per source/metric | — |
| GET | /api/ticker |
Teks ticker aktif | — |
| GET | /api/ticker?action=list |
Daftar semua ticker | — |
| GET | /api/siren |
Status sirene | — |
| GET | /api/services |
Status layanan | — |
| GET | /api/settings |
Setting non-rahasia | — |
| GET | /api/cameras |
Daftar kamera (URL dimasking) | — |
| GET | /api/cputemp |
Suhu CPU STB | — |
| GET | /api/timeline |
Timeline rekaman per tanggal | — |
| GET | /api/events |
Event log | — |
| GET | /api/history |
Riwayat telemetri | — |
| GET | /api/recordings |
Daftar file rekaman | — |
| POST | `/api/siren?action=on | off` | Trigger sirene |
| POST | /api/auth?pin=... |
Verifikasi PIN admin | PIN |
| POST | /api/pin |
Ganti PIN admin | PIN lama |
| POST | /api/ticker |
Tambah/ubah/hapus ticker | PIN |
| POST | /api/camera |
Tambah kamera | PIN |
| POST | /api/settings |
Ubah setting | PIN |
| DELETE | /api/camera |
Hapus kamera | PIN |
| DELETE | /api/recordings |
Hapus rekaman | PIN |
Catatan keamanan:
record.pyhanya listen di127.0.0.1. API ini tidak memiliki autentikasi sesi; endpoint tulis memakai PIN 8 digit, kecuali sirene (sengaja tanpa PIN). Jika tunnel publik mengarahkan/api/*ke:8088, endpoint tulis ini terekspos ke internet. Perlu pembatasan ingress atau auth tambahan.
6.3 Endpoint go2rtc (:1985)
| Path | Fungsi |
|---|---|
/api/streams |
Daftar stream + producer/consumer |
/api/streams?name=...&src=... (PUT) |
Tambah/ubah stream runtime |
/api/streams?src=... (DELETE) |
Hapus stream runtime |
/api/ws?src=... |
WebSocket WebRTC signaling |
/api/stream.mp4?src=... |
Stream MP4 |
/api/stream.m3u8?src=... |
HLS |
/kiosk.html, /ticker.html, /dashboard/ |
Static file dari /opt/camera/www |
6.4 Endpoint auth (:8099)
| Path | Fungsi |
|---|---|
GET /health |
Health check |
GET /auth/check |
Validasi cookie sesi (dipanggil nginx auth_request) |
GET /auth/login |
Halaman login |
POST /auth/login |
Proses login, set cookie jarpak_session |
POST /auth/logout |
Hapus sesi |
7. Model Data (SQLite /opt/camera/data.db)
| Tabel | Isi | Catatan |
|---|---|---|
settings |
Konfigurasi key/value | Termasuk serial_port, serial_baud, admin_pin_hash, disk_min_gb |
cameras |
Sumber kebenaran kamera | key, display_name, urls_json, enabled; dicerminkan ke go2rtc.yaml |
ticker_messages |
Teks berjalan | text, is_active, sort_order |
latest_telemetry |
Cache nilai terbaru | 1 baris per source+metric; dibaca API |
readings |
Riwayat telemetri mentah | Dipangkas/promosi oleh promoter |
hourly_avg |
Agregasi per jam | avg_v, min_v, max_v, n |
siren_state |
Status sirene saat ini | state, source, updated_at |
siren_events |
Audit trigger sirene | ts, action, reason |
service_status |
Status layanan terakhir | service, status, message, checked_at |
event_log |
Log kejadian aplikasi | level, source, message |
state_changes |
Perubahan state komponen | component, old_state, new_state, detail |
recordings |
Metadata rekaman lokal | Kosong karena recording dimatikan |
file_info |
Metadata file rekaman | Kosong/tidak aktif |
Alur data telemetri: readings (riwayat) → hourly_avg (agregasi) → latest_telemetry (cache untuk API). Promoter juga menjalankan retensi.
8. Alur Utama (Teks untuk Flowchart)
Format: setiap langkah diberi ID. Tanda
[ ]= proses,< >= keputusan,( )= kondisi akhir. Gunakan ID ini sebagai node saat menggambar.
A. Boot & Startup Order
[A1] STB power on
→ [A2] systemd mulai service dasar (network, chrony, tailscaled)
→ [A3] NetworkManager: eth0优先; jika eth0 down → WiFi failover
→ [A4] camera.service (go2rtc) start
→ [A5] camera-record.service start (Requires=camera.service)
→ [A6] jarpak-auth.service start (Before=nginx)
→ [A7] nginx.service start (:1984)
→ [A8] cloudflared.service start (tunnel keluar)
→ [A9] kiosk-hdmi-poll.timer aktif (cek tiap 10 detik)
→ [A10] wifi-failover-watchdog.timer aktif (cek tiap 30 detik)
→ [A11] cron: stb-health tiap 10 menit, cctv-backup 03.30
→ <A12> HDMI connected?>
├─ ya → [A13] kiosk.service start
│ → [A14] kiosk.sh: set display 1080p, tunggu 1985
│ → [A15] start overlay ticker (setsid)
│ → [A16] exec Chromium kiosk 1920×1080
│ → [A17] overlay Chromium 1920×68 di y=1012
│ → (A18) kiosk tampil
└─ tidak → [A19] kiosk tidak dijalankan / dihentikan
→ (A20) STB tetap melayani web, API, stream
Ketergantungan penting:
camera-recordbutuhcamera(go2rtc) hidup.jarpak-authharus siap sebelum nginx melayani dashboard.- Kiosk tidak menjadi syarat layanan web/API.
- Kiosk hanya hidup jika HDMI terdeteksi; ini menghemat CPU/RAM saat TV mati.
B. Alur Telemetri (ESP32 → DB → Tampilan)
[B1] ESP32 membaca sensor (PLN, aki, inverter, UPS, suhu)
→ [B2] ESP32 kirim blok data lewat serial (115200 baud)
→ [B3] record.py serial_reader_loop membaca baris
→ <B4> port serial ditemukan?>
├─ tidak → [B5] tunggu 5 detik, coba lagi
│ → [B6] simulator fallback menulis nilai dummy tiap 60 detik
│ → (B7) API tetap mengembalikan nilai (dummy)
└─ ya → [B8] parse blok `tel` / `state` / `danger`
→ [B9] tulis `readings` + update `latest_telemetry`
→ [B10] update `siren_state` jika ada perubahan
→ (B11) data siap dibaca API
→ [B12] dashboard/kiosk polling GET /api/telemetry tiap 15 detik
→ [B13] render kartu PLN, aki, inverter, suhu, beban
→ [B14] promoter agregasi `hourly_avg` + retensi `readings`
Kondisi saat ini: [B4] = tidak. Tidak ada /dev/ttyUSB*, /dev/ttyACM*, atau /dev/ttyESP32; serial_port kosong. Log [SERIAL] terhubung tidak ada. Jadi jalur yang aktif adalah B5 → B6 → B7 (simulasi).
Sumber nilai STB: stb.cpu_temp_c, stb.load_1, stb.mem_used_pct, stb.disk_free_gb dibaca dari sistem (real), bukan simulasi.
C. Alur Sirene
[C1] User tekan tombol sirene di dashboard/Android
→ [C2] POST /api/siren?action=on&reason=...
→ <C3> rate limit lolos?>
├─ tidak → [C4] HTTP 429, berhenti
└─ ya → [C5] apply_siren("on")
→ <C6> link serial tersedia?>
├─ tidak → [C7] state = Unknown / gagal
└─ ya → [C8] kirim perintah serial ke ESP32
→ [C9] ESP32 menyalakan sirene
→ [C10] ESP32 kirim balik state
→ [C11] update `siren_state` + `siren_events`
→ [C12] dashboard polling GET /api/siren tiap 5 detik
→ [C13] tampilkan status (On/Off/Unknown)
Catatan: durasi sirene sepenuhnya diatur ESP32; server hanya mengirim on/off. Sirene sengaja tanpa PIN agar bisa dipicu darurat, hanya dibatasi rate limit.
D. Alur Live View Kamera
[D1] NVR 192.168.0.20 menyediakan RTSP per channel
→ [D2] go2rtc membaca producer RTSP (ffmpeg, transcode H.264)
→ [D3] go2rtc menyediakan WebRTC (:8556), HLS, MP4 (:1985)
→ <D4> klien mana?>
├─ kiosk → [D5] http://127.0.0.1:1985/api/ws?src=...
├─ browser LAN→ [D6] http://192.168.1.11:1984/api/ws?src=...
└─ publik → [D7] https://jarpak.../api/ws?src=...
→ [D8] video tampil di kartu kamera
→ [D9] NVR menyimpan rekaman (bukan STB)
Kondisi saat ini: [D1] gagal (NVR beda subnet). go2rtc tetap punya producer, tetapi tidak ada consumer yang berhasil. record.py local recording dimatikan.
Catatan Android: aplikasi Android memakai stream H.264 dari NVR/go2rtc (bukan WebRTC). Alurnya: login → daftar kamera → buka stream → putar via ExoPlayer.
E. Alur Ticker (DB → API → Overlay Kiosk)
[E1] Admin menambah/ubah teks di dashboard
→ [E2] POST /api/ticker?action=add|set|delete&pin=...
→ [E3] record.py validasi PIN
→ [E4] tulis `ticker_messages`
→ [E5] overlay ticker polling GET /api/ticker tiap 60 detik
→ [E6] ticker.html membangun track teks
→ [E7] animasi CSS berjalan 60fps di window overlay
→ [E8] window overlay 1920×68 di posisi (0,1012), always on top
→ [E9] kartu ticker di halaman utama kiosk disembunyikan
(`visibility:hidden`, `animation:none`)
Mengapa overlay terpisah: halaman utama kiosk hanya mencapai ~41–49fps karena kompositing software 1080p + backdrop-filter. Window overlay yang kecil (1920×68) dengan --use-gl=disabled mencapai 60fps. Karena itu ticker dipindah ke window kedua, bukan di dalam halaman utama.
Geometri overlay: card 1895×52 di 12,3; label 141.09px; viewport 1752px; track 4869px; durasi 54.1 detik (45px/detik). Identik dengan tampilan utama.
Auto-restart: loop di kiosk-ticker-overlay.sh membunuh Chromium overlay lama (pkill -f user-data-dir) lalu menjalankan ulang; xdotool windowraise menjaga overlay di atas.
F. Alur Kiosk HDMI
[F1] kiosk-hdmi-poll.timer tiap 10 detik
→ [F2] baca /sys/class/drm/card0-HDMI-A-1/status
→ <F3> status terbaca?>
├─ tidak → [F4] diam (fail-safe), selesai
└─ ya → <F5> connected?>
├─ ya → <F6> kiosk active?>
│ ├─ tidak → [F7] systemctl start kiosk
│ │ → [F8] Xorg :0 vt1 + kiosk.sh
│ │ → [F9] display 1080p, Chromium, overlay
│ └─ ya → [F10] tidak apa-apa
└─ tidak → <F11> kiosk active?>
├─ ya → [F12] systemctl stop kiosk (hemat CPU/RAM)
└─ tidak → [F13] tidak apa-apa
Override manual: buat /etc/kiosk-hdmi.manual untuk menonaktifkan otomasi sementara; hapus untuk mengaktifkan lagi.
Kondisi saat ini: [F5] = tidak; kiosk.service sudah failed (bukan active), jadi poll tidak menghentikannya lagi. Saat HDMI dicolok, [F7] akan start.
G. Alur Website Publik & Autentikasi
[G1] User buka https://bagaswara.hibahkaranggeneng.site
→ [G2] Cloudflare (DNS + CDN + tunnel)
→ [G3] cloudflared → nginx :1984
→ <G4> path /dashboard/ ?>
├─ tidak → [G5] serve static (landing, profil, tim, publikasi)
└─ ya → [G6] nginx auth_request ke :8099/auth/check
→ <G7> cookie `jarpak_session` valid?>
├─ tidak → [G8] redirect 302 /login
│ → [G9] user isi username/password
│ → [G10] POST /auth/login
│ → [G11] verifikasi PBKDF2 + rate limit
│ → [G12] set cookie HMAC (12 jam, Secure)
│ → [G13] redirect /dashboard/
└─ ya → [G14] serve dashboard/index.html
→ [G15] dashboard polling API (telemetri 15 dtk, siren 5 dtk,
services 15 dtk, ticker 60 dtk, kamera 8 dtk)
Rute API publik [VERIFIKASI]: kode dashboard mengasumsikan /api/* diarahkan tunnel ke :8088 (record.py). Namun nginx lokal mengarahkan seluruh /api/ ke :1985 (go2rtc) dan hanya mengizinkan GET/HEAD. Artinya:
- Di LAN, dashboard memanggil
http://hostname:8088langsung; tetapirecord.pyhanya listen127.0.0.1, sehingga dari perangkat LAN lain panggilan ini gagal (nilai dummy). - Di publik, jika tunnel mengarahkan
/api/*ke:8088, API data jalan, tetapi endpoint go2rtc (/api/streams,/api/ws) juga ikut ke:8088dan gagal. - Diperlukan pemisahan path yang eksplisit (mis.
/api/data/*→ 8088,/api/stream/*→ 1985) atau nginx yang mem-proxy endpoint record.py.
Cache Cloudflare: HTML cf-cache-status: DYNAMIC; CSS/gambar statis HIT dengan max-age=14400.
H. Alur Backup & Health
[H1] cron 03.30 → cctv-backup.sh
→ [H2] tar database + config + website + kiosk assets
→ [H3] simpan /mnt/sdcard/backup/cctv-backup-YYYY-MM-DD.tar.gz
→ [H4] retensi 7 hari
[H5] cron */10 → stb-health.sh
→ [H6] catat suhu, load, memori, disk, eMMC life, service, NTP,
stream count, m3u8 latency, backup terakhir
→ [H7] tulis /mnt/sdcard/health/YYYY-MM-DD.log
→ [H8] tandai ANOMALY jika suhu >75°C, root >85%, ada service failed,
zombie >5
→ [H9] retensi log 14 hari
Kondisi saat ini: backup terakhir cctv-backup-2026-10-28.tar.gz ada. Health log mencatat ANOMALY: SVC_FAILED karena kiosk.service failed.
I. Alur WiFi Failover
[I1] NetworkManager memantau eth0
→ <I2> eth0 punya koneksi internet?>
├─ ya → [I3] putuskan WiFi, gunakan eth0
└─ tidak → [I4] aktifkan profil WiFi (UNS-SOLO / bil)
→ [I5] wifi-failover-watchdog.timer tiap 30 detik memeriksa ulang
→ [I6] cloudflared & tailscaled reconnect otomatis
Kondisi saat ini: eth0 aktif, WiFi down.
J. Alur Kegagalan (Failure Modes)
| Gejala | Penyebab | Deteksi | Perilaku sistem | Pemulihan |
|---|---|---|---|---|
| Kiosk mati | HDMI putus | kiosk-hdmi-poll baca status DRM |
kiosk tidak dijalankan; web/API tetap hidup | colok HDMI; poll start |
| Live view hitam | NVR beda subnet | ping/RTSP gagal; go2rtc tanpa consumer | kartu kamera error | perbaiki rute/NVR |
| Telemetri dummy | serial ESP32 tidak ada | log [SERIAL] kosong; serial_port kosong |
simulator menulis nilai | pasang/identifikasi port, set serial_port |
| Sirene tidak jalan | link serial putus | siren_state=Unknown |
perintah gagal | perbaiki serial |
| Dashboard publik tanpa data | rute /api/* salah |
nilai dummy / 404 | dashboard fallback dummy | pisahkan path API |
| Tunnel putus | QUIC idle/timeout | log cloudflared | reconnect otomatis | tunggu; cek jaringan |
| WebSocket putus ~100 dtk | batas idle Cloudflare | stream berhenti | reconnect klien | tidak bisa diubah dari STB |
| Kiosk patah-patah | software compositing | fps ~41–49 | ticker overlay 60fps | sudah dimitigasi overlay |
| Disk penuh | rekaman/lokal | health ROOT_FULL |
promoter retensi | hapus/arsipkan |
| STB reboot | listrik/watchdog | uptime reset | service auto-start | otomatis |
K. Alur Aplikasi Android (ringkas)
[K1] Buka aplikasi → [K2] login (PIN/akun)
→ [K3] muat daftar kamera dari API
→ [K4] pilih kamera → [K5] putar H.264 (ExoPlayer)
→ [K6] lihat telemetri + status
→ [K7] tombol sirene → POST /api/siren
→ [K8] ticker/teks berjalan
→ [K9] jika offline → tampilkan data terakhir / error
Detail endpoint Android ada di
D:\BRIEF-APLIKASI-BAGASWARA.md. Aplikasi hanya boleh diubah lewat brief tersebut; sourceD:\Workspace\Apps\Bagaswararead-only.
L. Narasi End-to-End (untuk presentasi)
“Sensor ESP32 mengirim data ke STB lewat serial. STB menyimpannya di SQLite dan menyajikan API. Dashboard dan kiosk mengambil API itu setiap 15 detik. Kamera IP mengalir ke NVR, lalu di-stream ulang oleh go2rtc di STB agar bisa ditonton di kiosk, web, dan Android. Ticker dikelola dari database dan ditampilkan di window overlay terpisah agar tetap 60fps. Semua akses publik lewat Cloudflare Tunnel dan login. Jika HDMI mati, kiosk otomatis berhenti; jika internet mati, kiosk tetap jalan dari server lokal.—
9. Status Saat Ini (Bukti Lapangan)
Diambil 28 Oktober 2026, 23.16 WIB:
| Item | Status | Bukti |
|---|---|---|
camera.service |
active | go2rtc listen 1985/8555/8556 |
camera-record.service |
active | record.py listen 8088 |
nginx |
active | listen 1984 |
jarpak-auth |
active | listen 8099 |
cloudflared |
active | QUIC registered sin19/sin14 |
tailscaled |
active | 100.77.104.5 |
kiosk.service |
failed | HDMI disconnected; failed sejak 18:08:46 |
| Overlay ticker | mati | child kiosk tidak jalan |
| HDMI | disconnected |
/sys/class/drm/card0-HDMI-A-1/status |
| NVR | tidak terjangkau | 192.168.0.20 beda subnet |
| Serial ESP32 | tidak terdeteksi | tidak ada ttyUSB/ttyACM/ttyESP32; log [SERIAL] kosong |
| Telemetri perangkat | simulasi | latest_telemetry update tiap 60 dtk dari simulator |
| Telemetri STB | real | CPU 38°C, load 0.41, mem 17.8% |
| Recording lokal | nonaktif | ENABLE_RECORDING=0 |
| Backup | OK | cctv-backup-2026-10-28.tar.gz |
| Health | anomali | ANOMALY: SVC_FAILED (kiosk) |
| Uptime | 1 jam 10 menit | reboot terakhir |
Nilai telemetri terakhir (simulasi): PLN 223.56 V (Hidup), aki 14.22 V (Discharging), inverter 225.0 V / 49.87 Hz / 4.53 A / 1019 W / 67.6%, ESP32 42.26°C, UPS 38.24°C.
10. Known Issues & Risiko
- NVR beda subnet — live view mati; perlu perbaikan jaringan.
- Serial ESP32 tidak teridentifikasi — telemetri simulasi; perlu cek kabel/port dan set
serial_port. - Rute API publik ambigu — potensi data dummy di LAN dan konflik
/api/go2rtc vs record.py di publik. - API record.py tanpa auth sesi — endpoint tulis mengandalkan PIN; sirene tanpa PIN (by design) dan rate limit.
- Cloudflare WebSocket idle ~100 detik — live view publik bisa terputus; tidak bisa diubah dari STB.
- Tidak ada hardware acceleration — Chromium software rendering; halaman utama 41–49fps; sudah dimitigasi overlay.
- Kiosk bergantung HDMI — jika TV mati, kiosk berhenti (fitur hemat daya, bukan bug).
- SD card wear — backup + health log + rekaman (nonaktif) menulis ke SD; pantau eMMC/SD health.
- Single point of failure — STB adalah satu-satunya edge; jika mati, semua tampilan lokal dan publik mati.
- Simulasi menyamarkan status sensor — dashboard tidak membedakan nilai nyata vs dummy; perlu indikator “sensor offline—.
11. Keamanan
- SSH: key
id_ed25519; akses via LAN/Tailscale. Password root sementaraolshop123— segera ganti. - Dashboard: login username/password; PBKDF2; cookie
jarpak_sessionHMAC 12 jam;Securedi host publik; rate limit 10 gagal/10 menit/IP. - Nginx:
auth_requestuntuk/dashboard/; security headers; hidden files deny;/api/config403;/api/hanya GET/HEAD. - record.py: bind
127.0.0.1; CORS*; PIN 8 digit untuk endpoint tulis; audit log; masking URL/kredensial di/api/cameras. - Cloudflare Tunnel: tidak ada port forwarding; akses publik lewat tunnel; token di
/etc/cloudflared/token(rahasia). - Tailscale: akses privat; relay “blr— latency 100–570ms.
- Risiko: jika ingress meneruskan
/api/*ke:8088, endpoint tulis (camera/ticker/settings) terekspos; sirene bisa dipicu siapa pun yang tahu URL (rate-limited). Perlu auth/ingress rule.
12. Lokasi File Penting
| Path | Isi |
|---|---|
/opt/camera/record.py |
API + DB + serial + simulator + promoter |
/opt/camera/data.db |
SQLite |
/opt/camera/go2rtc.yaml |
Konfigurasi stream (cermin tabel cameras) |
/opt/camera/www/ |
Static go2rtc: kiosk.html, ticker.html, dashboard/, assets |
/etc/opt/kiosk/kiosk.sh |
Start Xorg/Chromium + overlay |
/usr/local/bin/kiosk-ticker-overlay.sh |
Window overlay ticker |
/usr/local/bin/kiosk-display.sh |
Set HDMI 1080p |
/usr/local/bin/kiosk-hdmi-poll.sh |
Start/stop kiosk sesuai HDMI |
/usr/local/bin/sync-kiosk-ui.sh |
Sinkronisasi UI kiosk dari dashboard |
/usr/local/bin/jarpak-auth.py |
Auth service |
/etc/nginx/conf.d/jarpak.conf |
Konfigurasi nginx |
/etc/jarpak-auth/ |
Kredensial + secret (rahasia) |
/etc/cloudflared/token |
Token tunnel (rahasia) |
/etc/systemd/system/*.service |
Unit service |
/usr/local/bin/stb-health.sh |
Health check |
/usr/local/bin/cctv-backup.sh |
Backup harian |
/mnt/sdcard/backup/ |
Backup tar.gz |
/mnt/sdcard/health/ |
Log health |
/mnt/sdcard/cctv/ |
Rekaman lokal (nonaktif) |
/root/website-bagaswara-v2/ |
Sumber website (bind mount /var/www/jarpak) |
/root/.ssh/github_deploy |
Deploy key GitHub STB |
13. Checklist Verifikasi & Langkah Berikutnya
- HDMI/kiosk: colok HDMI → tunggu ≤10 detik → cek
systemctl is-active kioskdan window overlay. Pastikan resolusi 1920×1080, tidak 4K. - Serial ESP32: cek kabel/port; coba
ls -l /dev/ttyUSB* /dev/ttyACM* /dev/ttyESP32; setserial_portdi settings; restartcamera-record; cari log[SERIAL] terhubung; pastikan nilai berubah bukan simulasi. - NVR: perbaiki rute/subnet; tes
curlRTSP/ffprobe; cek/api/streamsada consumer; tes live view di kiosk, LAN, publik. - Rute API publik: verifikasi ingress Cloudflare; putuskan skema path (
/api/data/*vs/api/stream/*); sesuaikanAPI8088()/nginx; tes dari LAN dan publik. - Auth API: pastikan endpoint tulis tidak terekspos tanpa PIN; pertimbangkan auth untuk sirene atau pembatasan IP.
- Backup restore: uji ekstrak satu arsip ke direktori sementara; pastikan DB + config + website lengkap.
- GitHub: setelah repo dibuat dan deploy key ditambahkan, push dari STB dengan
GIT_SSH_COMMAND="ssh -i /root/.ssh/github_deploy"; jangan taruh token di URL. - Dokumentasi: perbarui dokumen ini setelah perbaikan NVR/serial/rute API.
14. Peta Node untuk Menggambar Flowchart
Gunakan tabel ini sebagai daftar node; tanda → adalah edge.
| Flow | Node | Edge |
|---|---|---|
| Boot | A1..A20 | A1→A2→A3→A4→A5→A6→A7→A8→A9→A10→A11→A12; A12-ya→A13→A14→A15→A16→A17→A18; A12-tidak→A19→A20 |
| Telemetri | B1..B14 | B1→B2→B3→B4; B4-tidak→B5→B6→B7; B4-ya→B8→B9→B10→B11; B11→B12→B13→B14 |
| Sirene | C1..C13 | C1→C2→C3; C3-tidak→C4; C3-ya→C5→C6; C6-tidak→C7; C6-ya→C8→C9→C10→C11; C11→C12→C13 |
| Kamera | D1..D9 | D1→D2→D3→D4; D4-kiosk→D5; D4-LAN→D6; D4-publik→D7; D5/D6/D7→D8; D1→D9 |
| Ticker | E1..E9 | E1→E2→E3→E4→E5→E6→E7→E8→E9 |
| Kiosk HDMI | F1..F13 | F1→F2→F3; F3-tidak→F4; F3-ya→F5; F5-ya→F6; F6-tidak→F7→F8→F9; F6-ya→F10; F5-tidak→F11; F11-ya→F12; F11-tidak→F13 |
| Web/Auth | G1..G15 | G1→G2→G3→G4; G4-tidak→G5; G4-ya→G6→G7; G7-tidak→G8→G9→G10→G11→G12→G13; G7-ya→G14; G14→G15 |
| Backup/Health | H1..H9 | H1→H2→H3→H4; H5→H6→H7→H8→H9 |
| WiFi | I1..I6 | I1→I2; I2-ya→I3; I2-tidak→I4; I3/I4→I5→I6 |
| Android | K1..K9 | K1→K2→K3→K4→K5→K6→K7→K8→K9 |
Saran tata letak gambar:
- Buat satu diagram besar dengan 5 kolom vertikal sesuai lapisan (Fisik → Edge → Data → Presentasi → Eksternal).
- Letakkan STB di tengah; tarik panah dari ESP32/NVR ke STB, lalu dari STB ke kiosk/web/Android.
- Buat sub-flow terpisah untuk Telemetri, Kamera, Ticker, Kiosk HDMI, dan Auth agar tidak terlalu padat.
- Beri warna berbeda: hijau = alur normal, merah = kegagalan, kuning = kondisi saat ini (kiosk mati, NVR unreachable, serial simulasi).
Dokumen ini disusun dari inspeksi langsung STB pada 28 Oktober 2026. Rahasia (password, token, kredensial RTSP) sengaja tidak dicantumkan.