# Tether API Android app that exposes your phone's connection status via HTTP API, accessible from tethered devices. ## Features - **Auto-start on tether**: Server automatically starts/stops when tethering is enabled/disabled - **Real-time status**: Connection type (5G/LTE/3G/WIFI), signal strength, carrier, battery level - **Simple REST API**: JSON responses, easy to integrate with any client - **No root required**: Works with standard Android permissions ## Installation Build with Android Studio or use the release APK. **Required permissions:** - `READ_PHONE_STATE` - Network connection type and carrier - `ACCESS_FINE_LOCATION` - Required by Android 10+ for signal strength - `POST_NOTIFICATIONS` - Service status notification ## API Reference Default port: `8765` Common gateway IPs when tethering: - USB tethering: `192.168.42.1` - WiFi hotspot: `192.168.43.1` ### GET /status Returns full phone status. **Response:** ```json { "connection": { "type": "LTE", "signal_dbm": -89, "signal_bars": 3, "carrier": "T-Mobile", "operator": "310260", "roaming": false }, "battery": { "level": 73, "charging": false }, "network": { "wifi_ssid": null, "ip_addresses": ["192.168.42.129"] }, "timestamp": 1702915200 } ``` **Fields:** | Field | Description | |-------|-------------| | `connection.type` | `5G`, `LTE`, `HSPA`, `3G`, `2G`, `WIFI`, `CELLULAR`, `NONE` | | `connection.signal_dbm` | Signal strength in dBm (-999 if unavailable) | | `connection.signal_bars` | 0-4 signal bars | | `connection.carrier` | Network operator name | | `connection.operator` | MCC+MNC code | | `connection.roaming` | Whether roaming is active | | `battery.level` | Battery percentage (0-100) | | `battery.charging` | Whether device is charging | | `network.wifi_ssid` | WiFi SSID if connected via WiFi | | `network.ip_addresses` | List of device IP addresses | | `timestamp` | Unix timestamp of response | ### GET /health Health check endpoint. **Response:** ```json {"status": "ok"} ``` ### GET / API information. **Response:** ```json { "name": "Tether API", "version": "1.0.0", "endpoints": [ {"path": "/status", "method": "GET", "description": "Get phone status"}, {"path": "/health", "method": "GET", "description": "Health check"} ] } ``` ## Client Examples ### Basic curl ```bash curl http://192.168.42.1:8765/status ``` ### Auto-discover phone IP ```bash #!/bin/bash for ip in 192.168.42.1 192.168.43.1 192.168.44.1; do if curl -s --connect-timeout 1 "http://$ip:8765/health" | grep -q "ok"; then echo "$ip" exit 0 fi done exit 1 ``` ### Waybar module **~/.config/waybar/config:** ```json { "custom/phone": { "exec": "~/.local/bin/phone-status.sh", "return-type": "json", "interval": 10, "format": "{}" } } ``` **~/.local/bin/phone-status.sh:** ```bash #!/bin/bash PHONE_IP="${PHONE_IP:-192.168.42.1}" PORT="${PORT:-8765}" status=$(curl -s --connect-timeout 2 "http://$PHONE_IP:$PORT/status") if [ -z "$status" ]; then echo '{"text": "N/A", "tooltip": "Phone not connected", "class": "disconnected"}' exit 0 fi type=$(echo "$status" | jq -r '.connection.type') bars=$(echo "$status" | jq -r '.connection.signal_bars') battery=$(echo "$status" | jq -r '.battery.level') case $bars in 4) signal="▂▄▆█" ;; 3) signal="▂▄▆░" ;; 2) signal="▂▄░░" ;; 1) signal="▂░░░" ;; *) signal="░░░░" ;; esac echo "{\"text\": \"$type $signal $battery%\", \"tooltip\": \"$type | Signal: $bars/4 | Battery: $battery%\", \"class\": \"$type\"}" ``` ### Python client ```python import requests def get_phone_status(ip="192.168.42.1", port=8765): try: r = requests.get(f"http://{ip}:{port}/status", timeout=2) return r.json() except: return None status = get_phone_status() if status: print(f"Connection: {status['connection']['type']}") print(f"Signal: {status['connection']['signal_bars']}/4") print(f"Battery: {status['battery']['level']}%") ``` ### KDE Plasmoid / Generic widget Most desktop widgets can execute shell commands. Use the curl/jq approach: ```bash curl -s http://192.168.42.1:8765/status | jq -r '"\(.connection.type) \(.connection.signal_bars)/4 \(.battery.level)%"' ``` ## Building ### Debug build ```bash ./gradlew assembleDebug # Output: app/build/outputs/apk/debug/app-debug.apk ``` ### Release build 1. Generate a keystore: ```bash keytool -genkey -v -keystore keystore.jks -keyalg RSA -keysize 2048 -validity 10000 -alias release ``` 2. Build with signing: ```bash export KEYSTORE_PASSWORD="your-password" export KEY_ALIAS="release" export KEY_PASSWORD="your-key-password" ./gradlew assembleRelease # Output: app/build/outputs/apk/release/app-release.apk ``` ## Contributing See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines. ## License GPLv3 - see [LICENSE](LICENSE)