Home Assistant wall screens on Android tablets, drawn with Remote Compose.
A Home Assistant add-on lays out screens of tiles, draws each one as a Remote Compose document and streams it to tablets running a small player app. Live state (on/off, brightness, temperatures, now playing) goes to the tablets as updates to variables in the document, so a state change never sends the screen again. Taps go back to the add-on, which calls Home Assistant; the tablets hold no Home Assistant token.
Screens wear a theme (built-in or made in the editor) by day and another in dark mode and at night; the add-on
draws every colour from it (server/.../render/Themes.kt), and the editor previews with the same colours.
The idea follows Tessera, which does this for ESP32 screens. No Tessera code or assets are used.
The editor, opened through ingress, with the made-up demo home:
![]() |
![]() |
| Lay out tiles on a grid, page by page | Pick a tile's entity, icon, colours, size and actions |
![]() |
![]() |
| Screens and the tablets showing them | Themes, built-in or your own |
tools/capture_screenshots.mjs retakes them from a running demo server.
| Path | What |
|---|---|
server/ |
The add-on: a Kotlin/Ktor server that talks to Home Assistant, renders documents and serves the editor |
player/ |
The Android player app (Android 8 and later) |
shared/ |
The layout model, the grid maths and the protocol, used by the server and the player |
editor/ |
The Vue 3 editor, opened through ingress |
catalogue/ |
Which tiles and cards each Home Assistant domain gets |
custom_components/remote_screens/ |
The Home Assistant integration (HACS) for screen settings and services |
addon/ |
The add-on's packaging, documentation and changelog |
docker/ |
Running without the Supervisor (Home Assistant Container or Core) |
- Add-on. In Home Assistant, Settings, Add-ons, Add-on store, add this repository
(
https://github.com/sickkick/remote-screens) and install Remote Screens. - Player app. Download it from the editor (Download the player app) or from the latest GitHub release.
- Integration (optional, for automations). In HACS, add this repository as a custom repository of type Integration, install Remote Screens and restart Home Assistant. The add-on announces itself, so Home Assistant then offers to set it up.
How to pair a tablet and lay out a screen is in addon/DOCS.md. Without the Supervisor, see docker/compose.yaml.
A screen's Kiosk lock (a switch in Home Assistant, or a setting in the editor) keeps its tablet on Remote Screens. Enrolled as a kiosk (Android's device owner), the tablet runs in lock task mode: no Home, Recents, notifications or power menu. Other tablets fall back to screen pinning. A Kiosk PIN unlocks the tablet locally.
- QR code. Factory reset the tablet, tap its Welcome screen six times and scan the code from the editor (Tablets, Enroll a tablet). The tablet joins Wi-Fi, downloads the app from the add-on and enrolls itself.
- adb, for tablets without the QR scanner:
./scripts/enroll-device-owner.sh --fresh remote-screens.apk(tablet with no accounts, USB debugging on).
addon/DOCS.md has the details: pinning, the PIN, and how to stop managing a tablet.
QR enrollment checks the APK's signing certificate. tools/package_addon.sh writes its checksum to version.json
when apksigner (Android SDK build tools, which need Java) is found; without it the add-on sends a checksum of the
APK file instead, which also works.
You need JDK 21, the Android SDK (for the player), Node 24 and Python 3.13.
./gradlew :shared:test :server:test # server and shared tests
./gradlew :server:installDist # the server, runnable as server/build/install/server/bin/server
./gradlew :player:assembleDebug # the player app
cd editor && npm ci && npm test && npm run build
python -m pip install -r requirements_test.txt && python -m pytest # the integrationA made-up home makes it possible to work without Home Assistant:
REMOTE_SCREENS_DEMO=1 REMOTE_SCREENS_DATA=/tmp/rs-demo \
REMOTE_SCREENS_STATIC=editor/dist \
REMOTE_SCREENS_INGRESS_PORT=18099 REMOTE_SCREENS_PLAYER_PORT=18100 \
server/build/install/server/bin/serverTo hand out the player app from it, add REMOTE_SCREENS_APK=<dir> with a folder holding remote-screens.apk and a
version.json such as {"versionCode": 100, "versionName": "0.1.0"} (tools/package_addon.sh writes both).
The editor is then at http://localhost:18099 (or run npm run dev in editor/, which proxies the API to it).
In the Android emulator, start the player with
adb shell am start -n tech.shaffersoftworks.remotescreens.player/.MainActivity --es server 10.0.2.2:18100.
The player's application ID was dev.remotescreens.player before; Android treats the renamed app as a different
one, so uninstall the old build first (kiosk tablets need a factory reset and a new enrollment).
docs/REMOTE_COMPOSE.md lists what we learned about Remote Compose 1.0.0-alpha21
and the workarounds the code relies on.
addon/VERSION and the version in addon/config.yaml must match. Pushing a tag v<version> runs
the release workflow: it builds the signed player app, packages the add-on,
pushes ghcr.io/<owner>/remote-screens-{amd64,aarch64} and attaches the APK to the GitHub release.
Tablets only accept an update signed with the key the app was first installed with, so every release must use the same key. The workflow reads it from these repository secrets:
| Secret | What |
|---|---|
PLAYER_KEYSTORE_BASE64 |
The keystore, base64 encoded |
PLAYER_KEYSTORE_PASSWORD |
Its password |
PLAYER_KEY_ALIAS |
The key's alias |
PLAYER_KEY_PASSWORD |
The key's password |
See NOTICE.




