Remote WebView Client
repository·main·Indexed 40 days ago
https://github.com/strange-v/remotewebviewclientAn ESPHome-compatible component and browser-based test client that allows ESP32 devices with displays to render complex web pages by streaming image tiles from a headless browser server via WebSockets.
What's inside Remote WebView Client
- Remote WebView Client is a client designed to connect to a Remote WebView Server. The server acts as a headless browser that renders web pages (such as Home Assistant dashboards) and streams them as image tiles over WebSocket to lightweight clients, typically ESP32-based displays. This allows low-power microcontrollers to display complex web interfaces.
Features of the Browser Test Client
mainThe Browser Test Client provides the following capabilities for testing remote WebView implementations:
- WebSocket Connection: Includes built-in reconnect and keepalive logic.
- Binary Protocol Support: Compatible with
Frame,Touch,OpenURL, andKeepalivepackets. - Rendering: Uses JPEG tile rendering to an HTML5 canvas.
- Input Simulation: Supports pointer/touch forwarding (down/move/up) with move coalescing.
Handling input and on-screen keyboards
mainThe Remote WebView Client does not provide a native on-screen keyboard. To enter text or interact with input fields, you have two options:
- Server-side keyboard: Enable and use the keyboard provided by the Remote WebView Server.
- Chrome DevTools: Use Chrome DevTools to interact with the server's headless browser when input is required.
Run the Browser Test Client locally
mainThe Browser Test Client allows for faster development loops by simulating a remote WebView connection in a browser, avoiding the need to reflash ESP devices.
To run the client locally:
- Install dependencies using
npm install. - Start the development server using
npm run dev. - Open the provided local Vite URL in your browser.
- Configure the
serveranddisplayparameters. - Click Connect to establish a connection.
- Use the Send open_url feature to perform navigation tests.
npm install npm run dev- Install dependencies using
Performance recommendations for Remote WebView Client
mainTo optimize the streaming experience, follow these guidelines:
- Full-frame updates: Set
full_frame_tile_countto1for the most efficient full-screen updates if your network and device memory allow it. - Frame rate: Keep
every_nth_frameset to1to avoid missing changes. Increasemin_frame_intervalto be slightly larger than the render time reported by the self-test (useurl: "self-test"to find this value). - Bandwidth and Speed:
- Set
max_bytes_per_msglarger than your maximum tile size (full-frame or partial). - Start
jpeg_qualityat85. If you need more speed or lower bandwidth, drop it toward70–75.
- Set
- Color issues: If colors appear swapped or tinted, set
big_endian: false. - Troubleshooting Red Tiles: A red tile or red screen indicates a tile payload exceeded
max_bytes_per_msg. To fix this, increasemax_bytes_per_msgor reducetile_size/jpeg_quality.
- Full-frame updates: Set
Install Remote WebView Client as an ESPHome component
mainThe client is implemented as an ESPHome external component. To install it, add the component to your ESPHome YAML configuration using the
external_componentsblock pointing to the GitHub repository. You must also ensure your ESP32 configuration includes necessary components likeesp_websocket_clientand a JPEG decoder (e.g.,bitbank2/jpegdec).external_components: - source: github://strange-v/RemoteWebViewClient@main refresh: 0s components: [ remote_webview ] remote_webview: id: rwv server: 172.16.0.252:8081 url: http://172.16.0.252:8123/dashboard-mobile/0Configure the remote_webview component
mainThe
remote_webviewcomponent is configured in ESPHome to define the connection to the server and the initial page to load. You can also tune performance parameters like tile counts, JPEG quality, and message size limits.remote_webview: id: rwv server: 172.16.0.252:8081 url: http://172.16.0.252:8123/dashboard-mobile/0 full_frame_tile_count: 1 max_bytes_per_msg: 61440 jpeg_quality: 85Configure RemoteWebViewBrowserClient connection settings
mainThe client uses a
UiSettingsstructure to manage connection parameters. These settings are persisted in the browser'slocalStorageunder the keyrwv-browser-client-settings.Settings Schema
Key Type Description serverstringThe server address (e.g., 172.16.0.252:8081)widthnumberViewport width heightnumberViewport height fullFrameTileCountnumberfftc- number of tiles for full framescalePercentnumberDisplay scale (e.g., 100for 100%)urlstringThe initial URL to open qualitynumberJPEG quality (1-100) maxBytesPerMsgnumbermbpm- maximum bytes per messageDefault Values
server:127.0.0.1:8081width:480height:480fullFrameTileCount:1scalePercent:100url:http://127.0.0.1:8123/quality:85maxBytesPerMsg:61440
Reference: remote_webview configuration parameters
mainThe following parameters are available for the
remote_webviewcomponent in ESPHome:| YAML key | Type | Required | Example | Description | |-------------------------|-----------|:--------:|----------------------------------|-------------| | `display_id` | id | ❌ | `panel` | Display to draw on. Optional, if only one display is defined in the YAML.| | | `touchscreen_id` | id | ❌ | `touch` | Touch input source. Optional, if only one touchscreen is defined in the YAML. | | `server` | string | ✅ | `172.16.0.252:8081` | WebSocket server address. Must be `hostname_or_IP:port`. | | `url` | string | ✅ | `http://…/dashboard` | Page to open on connect. | | `device_id` | string | ❌ | `"my-device"` or auto (`esp32-<mac>`) | Identifier used by the server. If not set, the component derives `esp32-<mac>` from the chip MAC and still sends it. | | `tile_size` | int | ❌ | `32` | Tile edge size in pixels. Helps the server choose tile packing; it’s best to keep it a multiple of 16. | | `full_frame_tile_count` | int | ❌ | `4` | Number of tiles the server should use for full-frame updates. | | `full_frame_area_threshold` | float | ❌ | `0.50` | Area delta (fraction of screen) above which the server should send a full frame. | | `full_frame_every` | int | ❌ | `50` | Force a full-frame update every N frames (0 disables). | | `every_nth_frame` | int | ❌ | `1` | Frame-rate divider. Server should send only every Nth frame. | | `min_frame_interval` | int (ms) | ❌ | `80` | Minimum time between frames on the wire, in milliseconds. | | `jpeg_quality` | int | ❌ | `85` | JPEG quality hint for the server’s encoder. | | `max_bytes_per_msg` | int (B) | ❌ | `14336` or `61440` | Upper bound for a single WS binary message. | | `big_endian` | bool | ❌ | `true` or `false` | Use big-endian RGB565 pixel order for JPEG output (set false for little-endian panels). Default is `true`. | | `rotation` | int | ❌ | 0, 90, 180, 270 | Enables software rotation for both the display and touchscreen. | | `on_frame_update` | action | ❌ | `- logger.log: "..."` | Action that gets triggered each time the display updates (maximum of 1 trigger per second) | | `current_url_sensor` | text_sensor | ❌ | `name: "Current URL"` | Exposes the URL currently loaded in the server's headless browser as an ESPHome Text Sensor. Supports on_value automations. |Build client-to-server command packets
mainThe protocol provides helper functions to construct binary packets for sending commands from the client to the remote WebView server:
buildTouchPacket(type, pointerId, x, y): Creates aTouchmessage (MsgType.Touch) for touch input.typemust be aTouchType(Down,Move, orUp).buildOpenUrlPacket(url, flags): Creates anOpenURLmessage (MsgType.OpenURL) to instruct the remote browser to navigate to a specific URL.buildKeepalivePacket(): Creates aKeepalivemessage (MsgType.Keepalive) to maintain the connection.
import { buildTouchPacket, buildOpenUrlPacket, buildKeepalivePacket, TouchType } from './protocol'; // Send a touch down event const touchDown = buildTouchPacket(TouchType.Down, 1, 100, 200); // Request navigation const nav = buildOpenUrlPacket('https://google.com'); // Send keepalive const keepalive = buildKeepalivePacket();Navigate to a URL via sendOpenUrl()
mainUse
sendOpenUrlto instruct the remote webview to navigate to a specific URL. This method returns a boolean indicating whether the command was successfully sent (returnsfalseif the WebSocket is not in anOPENstate).const success = client.sendOpenUrl('https://example.com'); if (!success) { console.error('Failed to send URL command: WebSocket not connected'); }Build a WebSocket URI with `buildWsUri`
mainUse
buildWsUrito construct the connection string for the WebSocket server. The function ensures the server address uses aws://orwss://scheme and appends required and optional query parameters for session configuration.Required Parameters:
server: The base URL of the WebSocket server.w: Width of the viewport.h: Height of the viewport.
Optional Parameters (
QueryOptions):id: A unique identifier for the session (defaults tobrowser-[8-char-uuid]if not provided).r,ts,fftc,ffat,ffe,enf,mfi,q,mbpm: Various numeric configuration/tuning parameters.
import { buildWsUri } from './protocol'; const uri = buildWsUri('ws://192.168.1.100:8080', { w: 480, h: 480, id: 'my-custom-client' }); // Result: "ws://192.168.1.100:8080/?id=my-custom-client&w=480&h=480"