Initial commit: Android Tether API app
Exposes phone connection status via HTTP API for tethered devices. Features: - Auto-start/stop server when tethering is enabled/disabled - REST API with /status and /health endpoints - Connection type, signal strength, carrier, battery info - Foreground service with persistent notification Stack: Kotlin 2.3, AGP 8.13, Gradle 8.13, compileSdk 36
This commit is contained in:
194
README.md
Normal file
194
README.md
Normal file
@@ -0,0 +1,194 @@
|
||||
# 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
|
||||
|
||||
1. Open in Android Studio
|
||||
2. Build > Build APK
|
||||
3. Install APK on your phone
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
Reference in New Issue
Block a user