Signal Deck
The oscilloscope for Home Assistant. A safe Python REPL embedded in Lovelace with built-in AI analyst, ECharts visualisations, and deep state exploration — powered by WebAssembly, runs entirely in your browser.
Features
Python REPL
Real Python running in WebAssembly via Monty. Safe, sandboxed, instant — no backend required.
ECharts Visualisations
History timelines, binary sensor lanes, and custom charts rendered with Apache ECharts.
AI Analyst
Built-in analyst powered by HA Conversation. Ask “why did this happen?” in plain English.
Deep State Exploration
Browse entities, attributes, rooms, and areas. Auto-resolve short names like kitchen_temp.
Calendar Events
Query calendar events with events(). Rich auto-rendering with colour-coded timelines.
Rich Auto-render
Entity cards, state tables, and charts render automatically. Just type an expression — the REPL picks the best view.
Safe by Default
Read-only state access. Service calls require explicit arming. No filesystem, no network, no eval.
Rust Shell Engine
Command parsing, data transforms, and render-spec generation in Rust compiled to WASM. Fast and tiny.
Installation
HACS (Recommended)
- Open HACS → Frontend → three-dot menu → Custom repositories
- Add
https://github.com/rsr5/signal-deckas category Dashboard - Search for Signal Deck and click Install
- Reload your browser
Manual
- Download
signal-deck.jsfrom the latest release - Copy it to
config/www/signal-deck.js - In HA → Settings → Dashboards → Resources, add
/local/signal-deck.jsas JavaScript Module - Reload your browser
Quick Start
Add a new card to any dashboard and paste this YAML:
type: custom:signal-deck
mode: embedded # or "overlay" for floating panel
height: 420
Once the card loads, try these commands in the REPL:
# List all entities
ls()
# Inspect a sensor
get("sensor.living_room_temperature")
# View 6 hours of history
history("sensor.living_room_temperature", "6h")
# Upcoming calendar events
events("calendar.home", "24h")
Card Configuration
| Option | Type | Default | Description |
|---|---|---|---|
mode | string | "embedded" | "embedded" (inline card) or "overlay" (floating panel) |
height | number | 420 | Card height in pixels (embedded mode) |
font_size | number | 13 | REPL font size in pixels |
startup | string[] | [] | Python commands to run on card load |
analyst_entity | string | — | Conversation agent entity for AI analyst |
Using the REPL
Signal Deck gives you a Python prompt inside your dashboard. Type any expression and press Enter to evaluate it. Results are automatically rendered as rich cards, tables, or charts when possible.
Magic Commands
Prefix commands with % for shell-level operations:
| Command | Description |
|---|---|
%ls | List entities (with optional domain/pattern filter) |
%get <entity> | Inspect a single entity with all attributes |
%history <entity> <period> | Fetch and chart entity history |
%events <calendar> <period> | List upcoming calendar events |
%rooms | Show rooms/areas and their entities |
%services <domain> | List available services for a domain |
%hist | Show command history |
%fmt <format> | Set output format (table, json, csv) |
%clear | Clear the REPL output |
:help | Show the built-in help reference |
Auto-resolve
You don't need to type full entity IDs. Signal Deck fuzzy-matches short names:
# These all work:
get("kitchen_temp") # matches sensor.kitchen_temperature
get("living_room_motion") # matches binary_sensor.living_room_motion
history("front_door", "12h") # matches lock.front_door
Keyboard Shortcuts
| Key | Action |
|---|---|
| Enter | Execute current line |
| Up / Down | Navigate command history |
| Ctrl+L | Clear output |
| Ctrl+C | Cancel / clear input |
| Tab | Auto-complete entity names |
Python API Reference
All functions are available at the top level — no imports needed.
State & Entities
| Function | Description |
|---|---|
ls() | List all entities. Optional: ls("sensor") to filter by domain. |
get(entity) | Get full state + attributes for an entity. Supports auto-resolve. |
state(entity) | Get just the state value as a string. |
attrs(entity) | Get just the attributes dict. |
attr(entity, key) | Get a single attribute value. |
show(value) | Explicitly render any value with rich auto-display. |
History & Diagnostics
| Function | Description |
|---|---|
history(entity, period) | Fetch state history. Period: "1h", "6h", "1d", "7d". |
changed(entity, period) | List state changes with timestamps. |
last_changed(entity) | When the entity last changed state. |
history() on a numeric sensor automatically renders an ECharts timeline. Binary sensors get lane-style charts.
Calendar Events
| Function | Description |
|---|---|
events(calendar, period) | Fetch upcoming events. Period: "24h", "7d", etc. |
Returns a list of CalendarEvent objects with these fields:
| Field | Type | Description |
|---|---|---|
summary | str | Event title |
start | str | Start time (ISO 8601 or date) |
end | str | End time (ISO 8601 or date) |
description | str or None | Event description |
location | str or None | Event location |
all_day | bool | Whether this is an all-day event |
# Upcoming 24 hours
events("calendar.home", "24h")
# Next 7 days from work calendar
events("calendar.work", "7d")
# Auto-renders as a colour-coded event timeline
Rooms & Services
| Function | Description |
|---|---|
rooms() | List all rooms/areas and their entity counts. |
room(name) | List all entities in a room. |
services(domain) | List available services. services("light") |
Utilities
| Function | Description |
|---|---|
ago(period) | Convert period string to datetime. ago("6h") |
now() | Current datetime. |
count(domain) | Count entities in a domain. |
domains() | List all entity domains. |
find(pattern) | Fuzzy search entities by name/ID. |
Charts
| Function | Description |
|---|---|
chart(entity, period) | Explicit chart rendering for an entity. |
compare([entities], period) | Multi-entity overlay chart. |
# Compare two sensors on one chart
compare(["sensor.indoor_temp", "sensor.outdoor_temp"], "24h")
# Explicit chart for a binary sensor
chart("binary_sensor.front_door", "12h")
AI Analyst
Signal Deck includes a built-in AI analyst that connects to any HA Conversation agent (Ollama, OpenAI, Google, local models). It can read your entity states and answer questions about your home.
Configure the analyst entity in your card YAML:
type: custom:signal-deck
analyst_entity: conversation.ollama # or any conversation agent
Then use the analyst button in the REPL toolbar, or ask directly:
# The analyst sees your current HA state and can run commands
# to investigate. It works best with questions like:
# "Why is the kitchen temperature rising?"
# "Which lights are on right now?"
# "Show me the front door history for today"
Architecture
Signal Deck is built in three layers with strict boundaries:
Data Flow
- User types a command in the REPL
- TypeScript passes input to the Rust WASM engine
- Rust parses, determines if HA data is needed, returns a host call request
- TypeScript fetches data via HA WebSocket API
- Rust processes data and returns a render spec (JSON)
- TypeScript renders the spec as cards, tables, or ECharts
Security Model
- Read-only by default — all state access is read-only
- No direct HA access from WASM — all I/O goes through TypeScript host functions
- No filesystem or network — the WASM sandbox prevents all external access
- Service calls require arming —
ha.arm()must be called before any service call - Auth stays in TypeScript — HA auth tokens never reach WASM
Development
Prerequisites
- Rust (stable) +
wasm-pack - Node.js ≥ 18 + npm
- A Home Assistant instance for testing
Building
# Clone the repo
git clone https://github.com/rsr5/signal-deck.git
cd signal-deck
# Install JS dependencies
npm install
# Build WASM + TypeScript
npm run build
# Or build each layer separately:
npm run build:wasm # Rust/WASM only
npm run build:ts # TypeScript/Rollup only
Dev Mode
# Watch mode (rebuilds on change)
npm run dev
# Copy dist/signal-deck.js to your HA config/www/ folder
# and add as a resource in Lovelace
Testing
# Run all tests
npm run test:all
# Rust tests (144 tests)
npm run test:rust
# TypeScript tests (19 tests)
npm run test
Project Structure
signal-deck/
crates/shell-engine/ # Rust WASM engine
src/
lib.rs # Entry point + host ABI
eval.rs # Expression evaluator
magic.rs # Magic commands + :help
render.rs # Render spec generation
calendar.rs # Calendar event handling
src/ # TypeScript
card.ts # Lovelace card element
repl.ts # REPL UI component
renderers/ # Render spec renderers
assistant/ # AI analyst integration
docs/ # This documentation site
dist/ # Built output
Contributing
We welcome contributions! Please see CONTRIBUTING.md for guidelines.
FAQ
How big is the bundle?
The JS bundle is ~2 MB and the WASM module is ~3.1 MB. Both are loaded lazily and cached by the browser. The WASM file uses content-hash cache busting for reliable updates.
Does it need a backend?
No. Signal Deck runs entirely in the browser using the HA WebSocket API. There is no custom integration or backend component to install.
Is it safe?
Yes. All Python runs in a WebAssembly sandbox with no filesystem or network access. State access is read-only by default. Service calls require explicit arming.
Which Python version does Monty support?
Monty implements a subset of Python 3 sufficient for data exploration — variables, functions, loops, list comprehensions, dicts, f-strings, and more. It is not a full CPython.
Can I use it with my existing dashboards?
Absolutely. Signal Deck is a standard Lovelace card. Add it to any view alongside your existing cards. The overlay mode gives you a floating panel that doesn't take up card space.
Does the AI analyst send data to the cloud?
That depends on your Conversation agent. If you use a local model (Ollama, llama.cpp), everything stays local. Cloud-based agents (OpenAI, Google) will process data on their servers.
Which Home Assistant version do I need?
Signal Deck requires Home Assistant 2024.1.0 or later for WebSocket API compatibility.
Can I run automations from the REPL?
Service calls are supported but gated behind an arming mechanism for safety. You must call ha.arm() before any service call, and a confirmation dialog is shown.
Changelog
See CHANGELOG.md for the full release history.
v0.1.0-alpha.1
Initial alpha release with:
- Embedded Python REPL (Monty via WebAssembly)
- Rust shell engine with magic commands and render specs
- Full Python API: state, history, calendar events, rooms, services, charts
- ECharts visualisations with auto-render
- AI analyst integration via HA Conversation
- Embedded and overlay display modes
- Entity auto-resolve and rich entity cards
- HACS-compatible packaging