mcpField
S
simulator-automation

simulator-automation

github.com/even-realitiesTesting & quality79135 installsUpdated 1w ago
Repository

About simulator-automation

A guide to the HTTP automation API exposed by Even Hub Simulator for developers. It covers inspecting simulator screenshots and logs, and sending touchpad input for automated interaction tests.

Key features

  1. 01Provides a health check endpoint
  2. 02Captures glasses and webview screenshots
  3. 03Reads and clears console logs
  4. 04Sends touchpad input

Use cases

  1. 01Automate checks for app startup
  2. 02Inspect display content and runtime logs
  3. 03Script gesture interaction tests

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/even-realities/everything-evenhub --skill simulator-automation

After installing, type/simulator-automationin Claude Code to confirm it loaded.

Details

From the project README

EvenHub Simulator Automation

The simulator exposes an HTTP API on localhost when launched with --automation-port <PORT>.

evenhub-simulator https://my-app.example.com --automation-port 9898

Base URL: http://127.0.0.1:<PORT>

API Reference

Health check
GET /api/ping
→ "pong"
Glasses screenshot

Returns the current LVGL framebuffer as image/png (576×288, RGBA).

GET /api/screenshot/glasses
→ image/png binary (RGBA)

RGBA format — critical for image analysis:

  • Background pixels: (R=0, G=255, B=0, A=0) — transparent (alpha = 0)
  • Lit/text pixels: (R=0, G=255, B=0, A=255) — opaque (alpha = 255)

Always work in RGBA mode. Do NOT convert to RGB — it drops the alpha channel and makes background pixels indistinguishable from text pixels (both appear as pure green).

from PIL import Image
img = Image.open('glasses.png')  # keep as RGBA — do NOT call img.convert('RGB')
pixels = img.load()
# Lit pixel test:
is_lit = lambda px: px[3] > 0   # alpha > 0
Webview screenshot

Captures the main browser webview using html2canvas. Returns image/png. May take a few seconds; times out after 10s.

GET /api/screenshot/webview
→ image/png binary
Console logs

Returns captured console.* output, uncaught exceptions, unhandled promise rejections, and failed fetch calls from the main webview.

GET /api/console
→ { "entries": [...], "total": N }

Each entry:

{ "id": 0, "level": "log|warn|error|info|debug|trace", "message": "...", "ts": 1712150400000 }

Prefixes for non-console sources:

  • [uncaught] ... — uncaught exception
  • [unhandledrejection] ... — unhandled promise rejection
  • [fetch] ... — failed fetch (non-ok status or network error)

Poll for new entries only:

GET /api/console?since_id=42
→ entries with id > 42

since_id must be a non-negative integer. Passing a negative value (e.g. -1) causes the server to return an error, not an empty list. For the first poll, omit the parameter entirely to retrieve all current entries, then track last_id from the response:

# First poll — no since_id
resp = requests.get(f"{BASE_URL}/api/console")
entries = resp.json()["entries"]
last_id = max((e["id"] for e in entries), default=0)

# Subsequent polls
resp = requests.get(f"{BASE_URL}/api/console?since_id={last_id}")

Clear the buffer:

DELETE /api/console

Timing caution: Startup logs (e.g. a "ready" signal) are emitted once and lost if you clear the buffer before reading them. Pattern: poll for the ready signal first, then clear if needed.

# Safe: check for ready signal BEFORE clearing
poll_until(target="APP_READY")
requests.delete(f"{BASE_URL}/api/console")  # only if you need a clean slate after
Glasses input

Send a touchpad action to the glasses display.

POST /api/input
Content-Type: application/json

{ "action": "up" | "down" | "click" | "double_click" }

Response: { "ok": true }

Actions map to the glasses touchpad:

  • up / down — scroll through list items or text
  • click — select the current item
  • double_click — triggers a system-level double-click event (typically "back" or "dismiss")

Automation workflow

  1. Verify the server is running: GET /api/ping
  2. Poll for app ready (without clearing console first): look for a known log message.
  3. Observe: Use /api/screenshot/glasses (RGBA) or /api/console to check state.
  4. Act: Send input via POST /api/input. After each action, wait briefly (~300ms) then confirm state changed.
  5. Iterate: Use since_id when polling console to avoid re-reading old entries.

Tips

  • The glasses display is 576×288 pixels, monochrome green. Screenshots are RGBA PNGs.
  • Input only works when the app has created an active event container. If no container is active, input is silently ignored.
  • double_click is typically used to go back or dismiss the current view.
  • Allow 4+ seconds after launching the simulator before polling — SDK init and createStartUpPageContainer take time.

Task

$ARGUMENTS

Comments

Markdown supported