Your private digital home.
A private Android dashboard for your Raspberry Pi.
Monitor it, wake devices, back up media, and review bank transactions without
handing control of your server to a cloud dashboard.
Screenshots · Features · Quick start · Agent · Privacy · Discussions · Contributing
OwnNode is built with Kotlin and Jetpack Compose and connects to the companion OwnNode Agent. The backend runs on your Raspberry Pi; the app connects over your trusted LAN, Tailscale, or an HTTPS reverse proxy.
OwnNode was previously named PiStats. Existing installs keep the application ID
com.zen.pistats, saved settings, backend API headers, and tester-group address, so the rename does not require reinstalling or reconfiguring the app.
- CPU usage
- RAM usage
- root filesystem disk usage
- uptime
- system temperature
- load average
- status for Docker containers discovered from the Pi and selected in the app
- backup drive state:
- connected or not
- mounted or not
- label and device when available
- optional Wake-on-LAN relay through the Pi, remotely enabled or disabled in app settings
- your server address and encrypted bearer token stay on your device
- the backend binds to localhost by default and supports private Tailscale access
- media goes directly from your phone to storage you configured
- bank SMS parsing happens locally; the complete SMS body is never persisted or uploaded
- every parsed transaction requires review before it can be sent to Actual Budget
app/ Android app
docs/ Android/backend contract notes
- Companion backend repository owns the Pi service implementation
- This app expects bearer-token auth
- Backend should stay on a trusted LAN, Tailscale network, or HTTPS reverse proxy
- Plain HTTP is accepted only for localhost, private LAN,
.local, and Tailscale addresses
- Kotlin
- Jetpack Compose
- Ktor client
- DataStore-backed settings
- polling-based dashboard
- capability-aware Wake PC dashboard action backed by persistent Pi settings
- resizable home-screen widget
- opt-in photo and video backup to Pi-managed Samba storage
- opt-in bank SMS parsing with an encrypted review queue and Actual Budget handoff
- safe private-network endpoint validation
GET /api/healthGET /api/servicesGET /api/statsPOST /api/wakeonlan/wakePOST /api/transactions/smswhenfeatures.transaction_syncis enabled
Example GET /api/stats response:
{
"host": "pi",
"uptime_seconds": 123456,
"cpu_percent": 18.4,
"memory": {
"used_mb": 512,
"total_mb": 1900
},
"disk": {
"root_used_gb": 51.0,
"root_total_gb": 917.0,
"root_used_percent": 6.0
},
"temperature_c": 48.2,
"load_average": [0.21, 0.34, 0.40],
"backup_drive": {
"connected": true,
"mounted": false,
"label": "PiBackup",
"device": "/dev/sdb2",
"mountpoint": null
},
"services": [
{ "name": "home-automation", "status": "up", "detail": "running" },
{ "name": "dns", "status": "up", "detail": "running" }
],
"generated_at": "2026-04-10T12:00:00Z"
}./gradlew :app:installDebugThen in the app:
- Open Settings
- Enter the Pi backend URL
- Enter the bearer token
- Test and save the connection
- Enable monitoring for the discovered services you care about
- Return to the dashboard
- Open Media backup from the cloud-upload action, grant library access, and enable automatic backup
- If the backend advertises transaction sync, open its dashboard card and grant access to future SMS messages; inbox history is never read
- Review detected transactions, approve the ones you want to import, then tap Sync approved transactions to send them to Actual Budget
The Android app accepts:
- HTTPS endpoints with a valid hostname
- cleartext HTTP only for localhost, RFC1918 LAN addresses,
.localnames, and Tailscale addresses
The app includes a home-screen widget that shows the same live stats contract in a large resizable layout.
Important limitation:
- the in-app dashboard refreshes every 15 seconds while visible
- the home-screen widget cannot refresh that aggressively on Android
- the widget updates after settings changes, app refreshes, and periodic background work
Backend deployment is handled in the separate backend repository. This Android client only needs the final Tailscale base URL and token.
For the client/backend contract, see:
- Implementation Plan
- Pi Deployment Guide
- Media Backup API
- Transaction Sync API
- SMS Corpus Analyzer
- Android Release Checklist
- OwnNode Brand Transition
OwnNode reads only media authorized through Android's media permissions and
streams it over the configured private route. The companion Pi backend must
implement POST /api/media/backup/items and writes the received content to the
configured library. Filesystem or network-share credentials are deliberately
never stored on the phone.
This feature does not make OwnNode appear in Android's Cloud media settings. Stock Android restricts that integration to OEM-nominated providers. OwnNode is instead an automatic private backup client.
OwnNode can parse future Indian bank transaction alerts locally, keep normalized events in an Android-Keystore-encrypted review queue, and send approved entries to the companion Pi backend. OTP, failed, pending, promotional, and balance-only messages are ignored, and the full SMS body is never persisted or uploaded.
Every newly parsed item that requires review posts a privacy-safe notification that opens the matching transaction's review dialog directly. Before approval, the user must verify a bank account fetched from the backend mapping file, the amount, debit/credit direction, and payee. Reference, date, time, and a local note can also be corrected. Changed field names, the selected account label, and the note remain encrypted on the phone; only the corrected normalized transaction and opaque mapping ID are uploaded.
Approving a transaction only marks it ready. OwnNode uploads reviewed entries after the user taps Sync approved transactions. All newly received transactions require review; automatic delivery can be added later after the review feedback has improved the parser.
Failed uploads show a copyable Diagnostic ID and safe error code. The same ID can be searched in the Pi backend journal, while Android retains per-transaction diagnostics in its encrypted queue. Neither side logs the SMS body or financial fields.
The companion backend must advertise both features.transaction_sync and a live
features.actual_budget health signal, expose safe labeled account options from
GET /api/transactions/accounts, and validate the selected mapping when an
approved event is uploaded. The dashboard and manual feature switch remain
unavailable unless Actual Budget is currently running, and background delivery
re-checks that state before every batch.
Because RECEIVE_SMS is a restricted Google Play permission, public distribution
requires the applicable Play Console declaration and approval; private sideloaded
installs are not subject to Play review.
Before expanding production parser rules, analyze reviewed examples with the SMS Corpus Analyzer, then add accepted and rejected examples as parser regression tests.
OwnNode is under active development. The monitoring dashboard, widget, Wake-on-LAN, media backup, and review-first transaction workflow are implemented. Closed-test participants should still expect beta updates and are encouraged to report reproducible findings in GitHub Discussions or Issues.
Run the local verification suite with:
./gradlew :app:testDebugUnitTest :app:lintDebug :app:assembleDebug


