-
-
Notifications
You must be signed in to change notification settings - Fork 13
Browser
The built-in browser lets you display web pages inside Ava, such as Home Assistant dashboards. It supports two render engines: System WebView and GeckoView.
The browser is a full-screen overlay that can display any web content on top of Ava.
Main Uses:
- Display Home Assistant dashboards
- Display custom control panels
- Display information websites
- Kiosk mode for old devices
Ava's browser is not a standalone kiosk browser app. It is a Service-based overlay renderer that runs inside the same process as the voice satellite, using SYSTEM_ALERT_WINDOW to draw web content on top of any Android UI. This architectural difference has significant implications.
| Aspect | Ava | Fully Kiosk | WallPanel |
|---|---|---|---|
| Rendering layer |
SYSTEM_ALERT_WINDOW overlay (Service) |
Full-screen Activity | Full-screen Activity |
| Process model | Runs inside voice satellite process | Standalone process | Standalone process |
| Coexistence with voice | Native, same process | Separate app, no voice | Separate app, no voice |
| Overlay z-order control |
OverlayZOrderCoordinator manages all overlays |
N/A (single layer) | N/A (single layer) |
| Lifecycle | Persists across app backgrounding, hide/show without destroying renderer | Activity lifecycle, renderer destroyed on background | Activity lifecycle |
| Communication with HA | ESPHome protocol (native, binary, encrypted) | REST API (HTTP polling) | MQTT or HTTP |
| Latency | Sub-100ms (persistent TCP + protobuf) | 1-5s (HTTP polling interval) | 1-5s (MQTT/HTTP polling) |
Fully Kiosk and WallPanel use a full-screen Activity as their rendering surface. This means:
- The browser takes over the entire screen. No other UI can coexist.
- Backgrounding the app destroys the WebView renderer. Returning requires a full page reload.
- Switching between browser and other features requires app switching, not layer switching.
Ava uses WindowManager.addView() with TYPE_APPLICATION_OVERLAY inside a Service. This means:
- The browser is a layer, not the whole screen. Notification scenes, floating windows, and the wake ripple can appear on top of the browser without destroying it.
- Hiding the browser does not destroy the renderer. The WebView stays alive in the background. Showing it again is instant, no page reload.
- The voice satellite, browser, notification overlay, and floating windows all run in one process with coordinated z-order. No IPC, no app switching.
Fully Kiosk communicates with HA via a REST API. HA polls the device every 30 seconds by default. Commands from HA to the device are also polled, adding latency.
WallPanel uses MQTT or HTTP, both polling-based.
Ava uses the ESPHome protocol over a persistent TCP connection with protobuf encoding:
- Real-time push: HA pushes state changes to Ava instantly. No polling delay.
- Real-time commands: HA sends browser commands (reload, eval JS, navigate) and they execute in milliseconds.
- Binary protocol: Protobuf is compact and fast. No JSON parsing overhead.
- Encrypted: The ESPHome native API supports encryption. REST and MQTT are typically plaintext on LAN.
- Single integration: Ava appears as one ESPHome device in HA with all entities (browser, sensors, switches, media player) in one place. Fully Kiosk requires a separate integration setup with IP and password.
| Feature | Ava | Fully Kiosk | WallPanel |
|---|---|---|---|
| Default engine | System WebView (Chromium) | System WebView | System WebView |
| Fallback engine | GeckoView pack (separate APK) | None | None |
| Old device support | Install Gecko pack for modern engine | Stuck with old WebView | Stuck with old WebView |
| Engine update | Update Gecko pack independently | Update via Play Store (may not work on old devices) | Update via Play Store |
On Android 5-7 devices, the system WebView is often outdated or cannot be updated (no Play Services). Fully Kiosk and WallPanel have no solution for this, their dashboards may fail to render modern CSS/JS.
Ava solves this with a separate GeckoView engine pack (com.example.ava.gecko). The Gecko engine is bundled in the pack and updated independently of the system. On Android 7 kiosk devices, Ava automatically grants the Gecko pack overlay permission and adds it to the vendor kill-list via root/Shizuku.
| Feature | Ava | Fully Kiosk | WallPanel |
|---|---|---|---|
| HA theme to browser | Bidirectional, real-time via JS bridge | One-way (HA CSS media query) | One-way (HA CSS media query) |
| Browser theme to HA | Yes, pushes dark mode state back to HA | No | No |
| Feedback loop prevention | 2-second debounce with suppression flags | N/A | N/A |
| Theme override | Ava can override HA theme or follow it | Follows system only | Follows system only |
Ava injects 313 lines of JavaScript (BrowserDarkModeScripts.kt) that:
- Reads
ha.hass.themes.darkModefrom the HA frontend - Subscribes to
themes_updatedevents - Applies the theme to
document.documentElementCSS variables - Pushes theme changes back to Ava's native
DarkModeManager - Ava then syncs to HA's
browser_displayentity
This is a true bidirectional sync. Change the theme in HA, the browser follows instantly. Change it in Ava, HA follows. Fully Kiosk and WallPanel can only follow the system dark mode setting.
| Command | Ava | Fully Kiosk | WallPanel |
|---|---|---|---|
| Navigate to URL | Yes (text entity, instant) | Yes (REST, polled) | Yes (MQTT/HTTP, polled) |
| Reload page | Yes (instant) | Yes (polled) | Yes (polled) |
| Execute JS | Yes (instant, eval command) |
No | No |
| Clear cache | Yes (instant) | Yes (polled) | Yes (polled) |
| Set brightness | Yes (instant) | Yes (polled) | Yes (polled) |
| Set volume | Yes (instant) | Yes (polled) | Yes (polled) |
| Fill form field | Yes (instant, fillInput with CSS selector) |
No | No |
| Extract page content | Yes (instant, Readability.js) | No | No |
| Show/hide browser | Yes (switch entity, instant, no reload) | Yes (brings app to foreground, reloads) | Yes (MQTT, reloads) |
The eval command is particularly powerful. You can inject any JavaScript into the dashboard from HA:
# Inject a cherry blossom animation
service: text.set_value
target:
entity_id: text.your_device_name_browser_command
data:
value: '{"eval": "document.body.style.animation = ..."}'Fully Kiosk and WallPanel cannot execute JavaScript on the page. You are limited to the commands they hardcoded.
| Feature | Ava | Fully Kiosk | WallPanel |
|---|---|---|---|
| Sync current URL to HA | Yes, automatic via browser_display entity |
Yes, via REST sensor (polled) | Yes, via MQTT (polled) |
| Latency | Instant (push) | 30s (poll) | 5-30s (poll) |
| URL normalization | Handles localhost, .local, IP addresses | None | None |
Ava normalizes URLs before syncing (adds http:// for localhost/.local/IP, https:// for everything else) to avoid HA storing broken URLs.
This is where Ava's architecture truly shines. On a single device, Ava can simultaneously display:
| Layer | Z-Order | Can coexist with browser? |
|---|---|---|
| Browser (WebView) | Base overlay | Yes (it is the base) |
| Notification scene | Above browser | Yes, appears on top |
| Floating clock | Above browser | Yes, appears on top |
| Vinyl cover | Above browser | Yes, appears on top |
| Weather overlay | Above browser | Yes, appears on top |
| Quick Entity panel | Above browser | Yes, appears on top |
| Wake ripple | Above browser | Yes, appears on top |
| Screensaver (web/image) | Above browser | Yes, replaces browser view |
With Fully Kiosk or WallPanel, you get one layer. If you want a clock overlay, you need a separate app. If you want a notification popup, you need a separate app. Each app switch destroys and reloads the browser.
Ava's OverlayZOrderCoordinator manages all overlay layers in one process. When a notification scene appears, it slides in on top of the browser. When it dismisses, the browser is still there, unchanged, no reload.
| Feature | Ava | Fully Kiosk | WallPanel |
|---|---|---|---|
| Screensaver type | Web page, image, Xiaomi wallpaper, clock | Image, clock | Image, clock |
| Web screensaver | Yes, separate ScreensaverWebViewService
|
No | No |
| Health monitoring | 15s load timeout, auto-recovery, 45min preventive refresh | None | None |
| Video compatibility | Patches HTMLVideoElement.play() for AbortError recovery |
N/A | N/A |
| Renderer priority |
IMPORTANT when visible, BOUND when hidden |
N/A | N/A |
| Proximity wake | Yes (via proximity sensor) | Motion detection | Motion/face detection |
Ava's screensaver can display any web page (e.g., a live clock widget, an animated wallpaper, a weather widget) with automatic crash recovery and video playback support. Fully Kiosk and WallPanel only support static images or basic clocks.
| Feature | Ava | Fully Kiosk | WallPanel |
|---|---|---|---|
| Userscript support | Yes (full GM API) | No | No |
| Script management | Built-in UI, install from URL/GreasyFork | N/A | N/A |
| GM_xmlhttpRequest | Yes (CORS-free) | N/A | N/A |
| GM_addStyle | Yes | N/A | N/A |
| GM_getValue/GM_setValue | Yes (persistent) | N/A | N/A |
Ava includes a full userscript manager based on Android-WebMonkey. You can install scripts from GreasyFork directly, or paste a URL. This allows custom CSS/JS injection for any dashboard without modifying HA configuration.
| Criterion | Winner |
|---|---|
| HA integration depth | Ava (ESPHome native, instant push) |
| Rendering on old devices | Ava (GeckoView pack) |
| Overlay coexistence | Ava (multi-layer, one process) |
| Dark mode sync | Ava (bidirectional) |
| Remote JS execution | Ava (eval command) |
| Userscript support | Ava (Tampermonkey) |
| Screensaver flexibility | Ava (web page with recovery) |
| Maintenance | Ava (active) vs WallPanel (dead) |
| Simplicity of setup | Fully Kiosk (install and go) |
| MDM features | Fully Kiosk (kiosk lockdown, app management) |
| Motion detection | Fully Kiosk / WallPanel (built-in) |
Ava is built for the HA-native kiosk use case: a wall tablet that shows a dashboard, listens for voice commands, displays notification scenes, and syncs everything in real-time. Fully Kiosk is a general-purpose kiosk browser with broader MDM features but no voice, no overlays, no userscripts, and no real-time protocol. WallPanel is unmaintained.
If you need pure kiosk lockdown (restrict apps, disable settings, manage multiple device types), Fully Kiosk is more mature in that area. If you need a HA-integrated dashboard display with voice, notifications, and real-time control, Ava is the better choice.
Ava supports two browser engines:
| Engine | Description | Use Case |
|---|---|---|
| System WebView | Uses Android system WebView | Most devices, lightweight |
| GeckoView | Mozilla Gecko engine pack | Old devices with outdated WebView |
GeckoView provides a modern browser engine for devices with outdated or missing system WebView.
Setup:
- Go to Settings -> Browser
- Select GeckoView as render engine
- Tap to download the engine pack
- When the install dialog appears, tap Install
- Wait for installation to complete
Notes:
- Requires downloading the engine pack (separate APK)
- Supports arm64-v8a and armeabi-v7a
- Can check for engine updates and uninstall from settings
- If the engine pack is not installed, browser falls back to System WebView
| Feature | Description |
|---|---|
| Full Screen | Web page fills entire screen |
| Pull to Refresh | Pull down to refresh page |
| JavaScript | Full JS support |
| Local Storage | LocalStorage supported |
| Page Scale | Initial zoom (0-500, 0=auto) |
| Font Size | Page font size percentage (50-300) |
| Touch / Drag | Toggle touch and drag interaction |
| Feature | Description |
|---|---|
| Render Mode | Hardware/software rendering switch |
| Dark Mode Sync | Sync dark mode with Ava and HA dashboard |
| User Agent | Switch browser identity (Android/Desktop/macOS/iOS) |
| Tampermonkey | Userscript support |
| Browser Sidebar | Slide-out menu on the edge |
| Gesture Navigation | Swipe from left edge to go back, swipe left to go forward |
| Browser Commands | Remote control via Home Assistant |
| Sync URL | Sync current browser URL back to HA |
| Clear Cache | Clear browser cache, cookies, and history |
| Scale Slider Entity | Expose a bidirectional scale slider in HA |
Go to Settings -> Browser
| Setting | Description | Default |
|---|---|---|
| Render engine | System WebView or GeckoView | System WebView |
| Pull to Refresh | Allow pull-down to refresh | On |
| Page Scale | Initial zoom (0=auto) | 0 |
| Font Size | Page font size percentage | 100 |
| Touch Enabled | Allow touch interaction | On |
| Drag Enabled | Allow drag operations | On |
| Render Mode | Hardware/software rendering | Hardware |
| Follow Dark Mode | Sync dark mode with app and HA | Off |
| User Agent | Browser identity | Default (Android) |
| Tampermonkey | Enable userscript support | Off |
| Browser Sidebar | Slide-out menu on the edge | Off |
| Gesture Navigation | Swipe to navigate back/forward | Off |
| Settings Button | Show gear icon in bottom right | Off |
| Back Key Hide | Press back key to hide browser | On |
| Sync Current URL | Sync browser URL to HA entity | Off |
| Advanced Control | Enable remote browser commands | Off |
| Scale Slider Entity | Expose scale slider in HA | Off |
| Mode | Description | Use Case |
|---|---|---|
| Hardware | Uses GPU, better performance | Most devices |
| Software | Uses CPU, better compatibility | Old devices or rendering issues |
| Option | Description |
|---|---|
| Default (Android) | Standard Android browser |
| Desktop (Windows) | Pretend to be Windows desktop |
| macOS (Safari) | Pretend to be macOS Safari |
| iOS (iPhone) | Pretend to be iPhone Safari |
Create a dedicated dashboard view for Ava:
# configuration.yaml
lovelace:
mode: yaml
dashboards:
ava-dashboard:
mode: yaml
filename: ava_dashboard.yaml
title: Ava
icon: mdi:tablet
show_in_sidebar: falseUse custom CSS to hide HA sidebar and header:
ha-sidebar { display: none !important; }
.header { display: none !important; }
home-assistant { --app-drawer-width: 0px; }service: text.set_value
target:
entity_id: text.your_device_name_ha_remote_url
data:
value: "http://your-ha-address:8123/lovelace/0"service: text.set_value
target:
entity_id: text.your_device_name_ha_remote_url
data:
value: ""# Show browser
service: switch.turn_on
target:
entity_id: switch.your_device_name_browser_display
# Hide browser
service: switch.turn_off
target:
entity_id: switch.your_device_name_browser_displayAfter enabling Advanced Control, you can remotely control the browser via Home Assistant services.
action: esphome.xxx_webview_command
data:
command: 'your command'| Command | Format | Description |
|---|---|---|
| Reload page | {"reload": true} |
Reload current page |
| Clear cache | {"clearCache": true} |
Clear browser cache |
| Set brightness | {"brightness": 128} |
Set screen brightness (0-255) |
| Set volume | {"volume": 50} |
Set volume (0-100) |
| Execute JS | {"eval": "alert('hello')"} |
Execute JavaScript code |
| Clear injected | {"eval": ""} |
Clear injected effects |
Ava includes a lightweight userscript manager based on the Android-WebMonkey project.
Supported GM APIs:
- GM_getValue / GM_setValue
- GM_addStyle
- GM_xmlhttpRequest
- GM_cookie
- GM_notification
Not Supported:
- GM_download
- GM_webRequest
- unsafeWindow
How to Use:
- Go to Settings -> Browser -> Tampermonkey
- Enable Tampermonkey
- Tap Add Script to install userscripts
- Manage installed scripts from the same page
A slide-out menu on the edge of the browser overlay for quick access to features.
Setup:
- Go to Settings -> Browser -> Browser Sidebar
- Enable sidebar
- Choose position (left or right edge)
You can use AI tools to generate custom animation effects (cherry blossoms, snow, stars, etc.) and inject them via the eval command.
Example: Cherry Blossom Animation
service: text.set_value
target:
entity_id: text.your_device_name_browser_command
data:
value: '{"eval": "!function(d,b,c,s){d=document,b=d.body,c=d.createElement(\"div\"),s=d.createElement(\"style\"),c.style.cssText=\"position:fixed;top:0;left:0;width:100%;height:100%;z-index:9999;overflow:hidden;pointer-events:none\",s.textContent=\".s{position:absolute;top:-10%;background:linear-gradient(135deg,#fff 20%,#ffb7c5 100%);border-radius:100% 0 120% 0;box-shadow:1px 1px 2px rgba(0,0,0,.1);animation:f linear infinite,w ease-in-out infinite alternate}@keyframes f{0%{opacity:0;transform:translateY(0) rotateX(0) rotateZ(0)}20%{opacity:1}100%{opacity:0;transform:translateY(110vh) rotateX(360deg) rotateZ(720deg)}}@keyframes w{0%{margin-left:-50px}100%{margin-left:50px}}\",d.head.appendChild(s),b.appendChild(c),setInterval(function(p,w,t){p=d.createElement(\"div\"),w=Math.random()*20+8,t=Math.random()*10+6,p.className=\"s\",p.style.cssText=\"left:\"+Math.random()*100+\"%%;width:\"+w+\"px;height:\"+w*1.4+\"px;animation-duration:\"+t+\"s,\"+(Math.random()*4+3)+\"s;animation-delay:-\"+Math.random()*8+\"s\",c.appendChild(p),setTimeout(function(){c.removeChild(p)},t*1e3)},100)}()"}'Clear Animation Effects
service: text.set_value
target:
entity_id: text.your_device_name_browser_command
data:
value: '{"eval": ""}'On large Home Assistant instances with thousands of entities, the HA frontend subscribes to every entity at page load (get_states + subscribe_entities with no filter). This firehose makes dashboards slow to load and sluggish, especially on low-powered kiosk devices that only need to display a handful of entities.
HA WebSocket Stripper is an open-source HA add-on that solves this. It is a lightweight reverse proxy that serves your real Lovelace dashboards (real frontend, real cards, Mushroom, button-card, everything) but strips the entity WebSocket down to only what each dashboard actually uses.
How it works:
- Passes all HTTP traffic straight through to HA (frontend bundles, auth, registries, lovelace config, custom-card resources, untouched)
- Intercepts only
/api/websocket:- Rewrites
subscribe_entitiesto include onlyentity_ids = <allowlist> - Filters the
get_statesresponse to the allowlist
- Rewrites
- The allowlist is computed from each dashboard's
lovelace/config(card tree walk + auto-entities expansion + template entity scan), plus youralways_forwardand minus yournever_forwardoverrides
Result: A kiosk page that previously downloaded thousands of entity states now downloads only a few dozen, with zero visual difference because it is still the real frontend.
- In HA, go to Settings -> Add-ons -> Add-on Store -> Repositories, add:
https://github.com/GabrielGoldsteinAnidea/HA-Websocket-Stripper - Install WebSocket Stripper, open Configuration, set your dashboards:
dashboards: - ava-dashboard - home-status always_forward: [] # e.g. ["/^sun\\./", "person.you"] never_forward: [] # e.g. ["/_battery$/"] strip_entities: true
- Start the add-on. Browse
http://<ha-host>:8099/ava-dashboard(port is remappable under the add-on's Network tab) - Point Ava's browser URL to this proxy address instead of the direct HA URL
For wall panels and kiosks, you usually want no password prompt. The add-on supports HA's trusted_networks auth provider with two built-in fixes:
-
host_network: true(built in) so HA sees the real browser IP, not the Docker gateway -
X-Forwarded-Fornormalization (built in) that strips IPv4-mapped IPv6 prefixes
Configure HA's configuration.yaml:
http:
use_x_forwarded_for: true
trusted_proxies:
- 127.0.0.1
- ::1
homeassistant:
auth_providers:
- type: trusted_networks
trusted_networks:
- 192.168.1.0/24 # your kiosk's LAN subnet
allow_bypass_login: true
- type: homeassistant # keep this for password loginThen restart HA Core.
Once the proxy is running, simply set Ava's browser URL to the proxy address:
service: text.set_value
target:
entity_id: text.your_device_name_ha_remote_url
data:
value: "http://192.168.1.2:8099/ava-dashboard"Ava's browser will load the dashboard through the proxy, getting the full real frontend but with a trimmed entity subscription. This is especially useful for:
- Old Android 5-7 devices with limited CPU and RAM
- Kiosks displaying a single dashboard with few entities
- Instances with 1000+ entities where dashboard load time exceeds 10 seconds
- Check if URL is correct
- Check network connection
- Try switching render mode (hardware/software)
- Try switching to GeckoView engine
- Check if HA is accessible
- Check network speed
- Simplify dashboard content
- Reduce animation effects
- Try GeckoView engine on old devices
- If you have a large HA instance (thousands of entities), see Large Instance Dashboard Acceleration above
- Check if Touch Enabled is on
- Check overlay permission
- Try restarting service
- Check if other overlays are blocking
- This may be a WebView issue on certain devices
- Try switching to GeckoView engine
- Check if the system WebView is up to date
- Enable Follow Dark Mode in Settings -> Browser
- Check if Ava dark mode is enabled
- Check if HA dashboard supports dark mode
- Check device architecture (arm64-v8a or armeabi-v7a required)
- Check network connection
- Ensure overlay permission is granted for the engine pack
- Try again later if download fails
Back to Home