Architecture
How WRTune communicates with OpenWRT routers under the hood.
WRTune communicates with your router through multiple channels, each chosen for the right task.
1. ubus JSON-RPC over HTTP (Primary) 🔗
The primary communication channel is ubus (OpenWRT’s inter-process communication bus), exposed via HTTP by the rpcd daemon:
HTTP POST → http://<router_ip>/ubus
Body: { "jsonrpc": "2.0", "id": 1, "method": "call", "params": [...] }
The core class OpenWrtApiService handles all ubus communication with these key behaviors:
- Authentication: Logs in via
session.loginubus call, caches the session token - Auto-refresh: If a call fails due to expired session, it transparently re-authenticates using stored credentials and retries once
- Batch calls:
batchCall()sends multiple ubus calls in a single HTTP POST (used by WiFi overview for efficiency) - Background isolate JSON decode: Large responses are decoded off the main thread via
compute()to prevent UI jank - Self-signed certs: Detects
HandshakeException, throwsCertificateException, and supportsloginWithTrustedCert() - Timeout: 5-second connect and receive timeouts
2. The WRTune Engine (Custom rpcd Script) 🔗
The WRTune Engine is a custom shell script at /usr/libexec/rpcd/wrtune that creates a wrtune ubus namespace. It handles advanced features like WiFi management, client blocking, guest WiFi, and Wake-on-LAN — tasks that stock OpenWRT’s rpcd doesn’t expose natively.
3. Direct uci / luci-rpc Calls 🔗
For data retrieval, WRTune calls standard ubus namespaces directly:
| Namespace | Used For |
|---|---|
uci | Read/write UCI config (firewall, DHCP, wireless) |
luci-rpc | DHCP leases, host hints, realtime stats |
iwinfo | Radio info, associated stations, signal strengths |
hostapd.* | Wireless client lists |
file | Execute shell commands (nlbw, vnstat for statistics) |
system | Board info, uptime, CPU/RAM health |
4. SSH (Engine Installation & Terminal) 🔗
- Engine installation:
HeadlessSshRunnerconnects via SSH, pipes the WRTune script content, and waits for a success marker - Interactive terminal:
TerminalServicespawns a DartIsolaterunningsshWorkerwithdartssh2. All terminal I/O streams between isolates viaSendPort/ReceivePort— keeping SSH off the UI thread
5. AdGuard Home API 🔗
The DNS Control feature communicates directly with an AdGuard Home instance on the router via its REST API (not ubus). A separate Dio instance handles AdGuard Home’s HTTP API for DNS stats, filtering rules, and blocked services.
Session Management 🔗
The _sessionRefresher callback pattern allows the API service to silently re-login when a session expires, without user intervention. The AuthRepository provides stored credentials to the API service for transparent refresh.