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:

{
  "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:

{"status": "ok"}

GET /

API information.

Response:

{
  "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

curl http://192.168.42.1:8765/status

Auto-discover phone IP

#!/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:

{
    "custom/phone": {
        "exec": "~/.local/bin/phone-status.sh",
        "return-type": "json",
        "interval": 10,
        "format": "{}"
    }
}

~/.local/bin/phone-status.sh:

#!/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

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:

curl -s http://192.168.42.1:8765/status | jq -r '"\(.connection.type) \(.connection.signal_bars)/4 \(.battery.level)%"'

Building

Debug build

./gradlew assembleDebug
# Output: app/build/outputs/apk/debug/app-debug.apk

Release build

  1. Generate a keystore:
keytool -genkey -v -keystore keystore.jks -keyalg RSA -keysize 2048 -validity 10000 -alias release
  1. Build with signing:
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 for guidelines.

License

GPLv3 - see LICENSE

Description
No description provided
Readme GPL-3.0 887 KiB
Languages
Kotlin 87.7%
Just 12.3%