# Telegram Reset Button untuk Notifikasi Expired (MSR Hotspot) > Ringkasan perubahan arsitektur notifikasi expired hotspot & tombol "๐Ÿ”„ Reset" via Telegram. > Tanggal: 1 Agu 2026 ยท RouterOS v6.49.6 ยท Mikhmon (Docker) --- ## 1. Masalah Awal 1. Notifikasi "User X expired" sebelumnya dikirim oleh `notify-expire.php` di server Mikhmon, yang menampilkan inline keyboard **๐Ÿ”„ Reset** dengan `callback_data=reset_`. 2. Router (MikroTik) tidak bisa menjangkau path lama (`192.168.100.6`, sudah mati). Scheduler di router mengirim notifikasi ke URL Telegram lama yang tidak lagi berfungsi. 3. Akibatnya pesan expired terkirim **tanpa tombol Reset**, dan callback reset tidak berfungsi. ## 2. Solusi Baru (Arsitektur) ``` [RouterOS Scheduler] --/tool/fetch sendMessage--> [Telegram Bot] --Kirim ke Grup (thread "Notif Expire") ^ [User klik ๐Ÿ”„ Reset] --> callback_query --> [Bot] --> poller getUpdates | v [Host rl] cron tiap menit --> msr-poller.sh --> docker start mikhmon | v telegram-cb.php (di container) --> RouterOS API reset user | v Telegram: "โœ… {user} has been reset" ``` ### Komponen | Komponen | Lokasi | Peran | |---|---|---| | Scheduler RouterOS | Router 192.168.100.2 | Kirim pesan expired + `reply_markup` tombol Reset langsung ke Telegram | | Telegram Bot | `5115036608:AAGey...` | Terima/teruskan pesan & callback | | Cron host | `/usr/local/bin/msr-poller.sh` di `rl` | Setiap menit: `docker start mikhmon` + curl `telegram-cb.php` | | `telegram-cb.php` | `/var/www/html/` di container `mikhmon` | getUpdates โ†’ reset user di RouterOS โ†’ jawab callback + kirim konfirmasi | | `lib/routeros_api.class.php` | `/var/www/html/lib/` | Koneksi RouterOS API dari PHP | ## 3. Perubahan yang Dilakukan ### 3.1 Scheduler RouterOS (Family, Bulanan2, Bulanan4) `on-event` scheduler sekarang melakukan `/tool/fetch` ke Telegram `sendMessage` dengan: - `chat_id=-1002554941429`, `message_thread_id=42` (thread "Notif Expire") - `text=" . $name . "+expired` - `reply_markup` = JSON inline keyboard **URL-encoded**: ``` %7B%22inline_keyboard%22%3A%5B%5B%7B%22text%22%3A%22%F0%9F%94%84%20Reset%22%2C%22callback_data%22%3A%22reset_" . $name . "%22%7D%5D%5D%7D ``` yang setara dengan: ```json {"inline_keyboard":[[{"text":"๐Ÿ”ด Reset","callback_data":"reset_"}]]} ``` Contoh cuplikan on-event Family: ``` tool fetch url=("https://api.telegram.org/bot5115036608:AAGey.../sendMessage?chat_id=-1002554941429&message_thread_id=42&text=" . $name . "+expired&reply_markup=" . "%7B%22inline_keyboard%22%3A...%22reset_" . $name . "%22%7D%5D%5D%7D") mode=https http-method=get keep-result=no ``` **Penting:** deduplikasi (`:if ($curlim = "")`) tetap dipertahankan agar setiap user hanya dikirim sekali. ### 3.2 Container Mikhmon โ€” Install php81-curl Container PHP 8.1 (Alpine) awalnya tanpa ekstensi cURL โ†’ `telegram-cb.php` error HTTP 500. ```sh docker exec -u root mikhmon apk add --no-cache php81-curl ``` ### 3.3 Perbaikan include path `telegram-cb.php` Dari `dirname(__DIR__) . '/lib/routeros_api.class.php'` โ†’ `__DIR__ . '/lib/routeros_api.class.php'` (2 tempat), karena file berada langsung di `/var/www/html/`. ### 3.4 Poller Host (atasi sablier) Container `mikhmon` dikelola **sablier** (traefik plugin) yang mematikannya setelah **5 menit idle** โ€” cron di dalam container tidak bisa diandalkan. Solusi: cron di **host** yang men-starter container lalu memanggil callback. `/usr/local/bin/msr-poller.sh`: ```bash #!/bin/bash CB_KEY="msr-2026-reset" URL="http://172.18.0.15/telegram-cb.php?key=${CB_KEY}" docker start mikhmon >/dev/null 2>&1 sleep 1 curl -s -m 30 "$URL" >/dev/null 2>&1 ``` Crontab host (`crontab -l`): ``` * * * * * /usr/local/bin/msr-poller.sh >/dev/null 2>&1 ``` Catatan: - `docker start` idempotent (kalau sudah jalan, no-op) โ†’ otomatis menjaga container hidup. - Polling maksimal latency ~1 menit setelah klik tombol. ### 3.5 Callback Handler `telegram-cb.php` - Auth via `?key=msr-2026-reset` (403 kalau salah). - `getUpdates` (hanya `callback_query`). - Untuk `data` berawalan `reset_`: 1. Cari user di `/ip/hotspot/user/print?name=` 2. `set limit-uptime=0, comment=''` + `reset-counters` 3. Hapus scheduler bernama `` (jika ada) 4. `answerCallbackQuery` (`โœ… {user} reset!`) 5. `sendMessage` ke chat/thread: `โœ… *{user}* has been reset\nReady to use again` - User tidak ditemukan โ†’ `answerCallbackQuery` alert `User {user} not found` (tanpa pesan). - Meng-konfirmasi offset via `getUpdates?offset=` setelah diproses. ## 4. Verifikasi | Item | Hasil | |---|---| | Pesan expired + tombol Reset muncul di grup | โœ… Bubble punya `reply-markup-button` "Reset" | | Klik tombol โ†’ callback `reset_` sampai ke bot | โœ… `data: "reset_TMR-1"` via getUpdates | | Poller cron memproses callback | โœ… `processed: 1` | | User di-reset di router | โœ… `limit-uptime` 10s โ†’ None (unlimited), counters reset | | Scheduler user dihapus | โœ… | | Konfirmasi bot di grup | โœ… `msr_net: TMR-1 has been reset` (09:11) | Test user `TMR-1` dibuat khusus lalu dihapus setelah verifikasi. ## 5. Operasional & Troubleshooting ### Cek status - Poller: `ssh rl "cat /usr/local/bin/msr-poller.sh; crontab -l | grep poller"` - Container: `ssh rl "docker ps --filter name=mikhmon --format '{{.Status}}'"` - Callback pending: `curl 'http://172.18.0.15/telegram-cb.php?key=msr-2026-reset'` โ†’ harus `processed: 0` / `no updates` - Webhook tidak terpasang (poller getUpdates aman): `getWebhookInfo` โ†’ `url: ""`, `allowed_updates:["callback_query"]` ### Gejala umum - **HTTP 500 dari telegram-cb.php** โ†’ cek cURL: `docker exec mikhmon php -r 'var_dump(function_exists("curl_init"));'` - **Container mati** โ†’ sablier mematikannya setelah 5m idle; poller harusnya men-starter. Cek log poller/cron. - **Callback tidak terproses** โ†’ JANGAN baca `getUpdates` manual (maju offset & poller kehilangan callback). Biarkan poller cron yang memproses. - **Tombol tidak muncul** โ†’ `reply_markup` tidak ter-encode dengan benar; cek `verify-markup.py` & on-event scheduler. ## 6. Kredensial & Referensi - Router: `192.168.100.2`, API `remote.vpnmurahjogja.my.id:33206`, login `mi4`/`m14` - Bot: `5115036608:AAGeyXVq5eNvdAkaCQHU9NfH16uAAiSKiuk` - Chat/Grup: `-1002554941429`, thread `42` ("Notif Expire") - Container: `mikhmon` (animegasan/mikhmon:v3-latest) di host `rl` (`root@100.100.31.46`, ssh alias `rl`, key `~/.ssh/pl`) - Callback secret: `msr-2026-reset` - Container IP: `172.18.0.15` ## 7. Skrip Bantu (folder `C:\Users\Admin\dev\mikhmon-fix\`) | Skrip | Fungsi | |---|---| | `patch-notif2.py` | Patch on-event scheduler โ†’ tambah `reply_markup` Reset button | | `verify-markup.py` | Verifikasi on-event berisi `reply_markup` & `reset_` | | `verify-notif.py` | Verifikasi isi scheduler (api.telegram.org, tidak ada URL lama) | | `dump-sched.py` | Dump penuh on-event scheduler | | `telegram-cb.php` | Callback handler (sumber; di-deploy ke container) | | `poller.sh` | Poller host (sumber; di-deploy ke `/usr/local/bin/msr-poller.sh`) | | `mk-user.py` / `rm-user.py` | Buat / hapus user test | | `send-expired-tmr.py` | Kirim pesan expired + tombol untuk user tertentu | | `check-reset.py` | Cek limit-uptime & scheduler user setelah reset | ## 8. Catatan - Bot menampilkan tombol sebagai "Reset" โ€” teks `๐Ÿ”„` (U+1F504, `%F0%9F%94%84`) di-render Telegram sebagai ikon ๐Ÿ”„. - `keep-result=no` di scheduler fetch (tidak menyimpan file respons di router). Saat debug bisa ubah `keep-result=yes` untuk lihat file `sendMessage?...`. - Jika tombol ditekan dua kali, user kedua dikirim ulang notif "expired" (karena sudah reset, limit-uptime unlimited โ†’ tidak ada scheduler baru sampai limit diubah lagi).