Home Assistant environment designed for custom component developers and tinkerers. Makes it easy as pie!
Its aims are:
- exploring of the APIs in context of a live working instance
- trialling out snippets of code
- debugging code
- hotfixing issues that don't have built in support to do so from existing components.
This is primarily for developers of custom components, and their agents, though may be of interest for other folk tinkering with Home Assistant. It is a potentially sharp tool, so NOT appropriate for general Home Assistant users.
A HACS component that taps into the Home Assistant and acts as a session server over web sockets.
All of the objects in Home Assistant - entities, devices, actions, areas, labels etc - are represented live in an Object Explorer, a tree structure, nested by the "." split name and with the object type and integration_key at the root. The properties of objects can be inspected.
Logical
- <integration>
- <domain>
- <id>
Physical
- alexa_devices
- media_player
- kitchen_show
- notify
- bedroom_echo
- action
- play_sound
- device # maps to a device config entry, same physical device may have several
- 9949349049030434348434
The object browser makes the largely correct assumption that everything useful lives in an integration
- Add button re-using Home Assistant dialogs
- Delete, with multi-select, calling regular home-assistant checks
- Copy and paste, similar to how it works in front end for duping automations etc
- Filter by area/label/floor/category/platform/domain/free text
- Handle legacy yaml entities without a
unique_id - Actions that don't live in integrations, and other orphans
The REPL shell is a full Python REPL shell, implemented as a VSCode NotebookController, with multi-line editing, history etc, living inside an asyncio loop that exposes the live Home Assistant instance as
hass- theHomeAssistantclass at the root of the Python APIobj[]- the object tree exposed as a dictionary object
So I can write code at the command line like:
pir=obj["/rflink/binary_sensor/hall_pir"]
pir.state="on" # non-strict mode, sets entity state with repl as contextThe return value of the object is returned to the shell, value printed and available to Python code as _. Tracebacks are printed also, as if they were local (in general everything feels like its local)
There is another special object, this which is the object currently highlighted in the Object Browser.
This switch controls trade-off between shell convenience and ability to trial working code for a component.
- Control to switch it off in the toolbar of the REPL.
on- Access to the core API is exactly as it would be in regular component code.
off- Subset of methods that don't require arguments can be accessed like properties, even if they aren't defined that way, and very common ones, like
stateare auto-wired to be gettable and settable. asyncmethods are automatically awaited- 'RegistryEntity
andEntitymerged,.hass` stripped
- Subset of methods that don't require arguments can be accessed like properties, even if they aren't defined that way, and very common ones, like
- Drop down button to switch context between different Home Assistant instances
- Read-only Mode
- Control to switch it off in the toolbar of the REPL.
- Caveat about side-effects of supposedly read-only calls and difficulty of knowing what's really read-only. Possibly blanket ban on calling actions.
- Click thru from stacktrace to hass code
- Intellisense, e.g. pop up attribute suggestions when pressing
. - Auto clone the source of current HA instance and keep tag aligned with release
- On demand also for custom components, both this and core can be disabled for space constrained devices, with
inspect.getsourceas backup
- On demand also for custom components, both this and core can be disabled for space constrained devices, with
- Notebook support, e.g. Marimo
- CLI
- safe(r) mode - remove things like stop
- Event subscription and visualization
- LSP?
- Everything runs in the async loop, non async code wrapped as async in HA compatible way. Warn about blocking calls in non-strict
- Persisting context across invocations
- Appdaemon support
- Multiple sessions with a session switcher and optional names
- Ability to reload custom component classes within the shell
reload(x)for fast feedback debug/development - Redirect log statements captured
- Tight authN / authZ / encryption
- NOT a debugger, but may do more to complement one
- NOT pyscript, focuses on actual python even at expense of general usability or home assistance access, no script execution support outside of the repl
- Basic REPL
- strict mode only
hassbinding only (entities accessible via usual hass calls)- packaged as CLI with
execand interative mode, session name and session reset flag andHASS_URL
- Object browser
- out of scope
- so also no
thisorobj[]
- VSCode integration
- out of scope
- HACS Component
- server side session management (session reused indefinitely until reset)
- stdout and traceback reflection to shell
- admin-only websocket
- clean up sessions after x hours
Layout:
custom_components/dev_shell_server/: the HACS integration (nameddev_shell_serverto distinguish it from the CLI below).session.pyis the execution engine (no HA imports);websocket_api.pyexposes the admin-onlydev_shell_server/exec,dev_shell_server/resetanddev_shell_server/sessionscommands.src/dev_shell/: thedev_shellCLI (exec, interactive REPL,reset,sessions).dev/: a throwaway HA config withdemo:entities, plus run and bootstrap scripts.
Dev instance (devcontainer, or directly on a host with Python 3.14):
dev/setup.sh # installs HA into its own venv + the CLI (devcontainer runs this)
dev/run-ha.sh # HA on :8123 with custom_components/dev_shell_server symlinked in
uv run python dev/bootstrap.py # onboard (user dev/dev) and write dev/.env with a tokenUsing it (host or container):
set -a; . dev/.env; set +a
uv run dev_shell # interactive
uv run dev_shell exec 'hass.states.get("sun.sun")'
uv run dev_shell exec - <<'PY'
await hass.services.async_call("light", "toggle", {"entity_id": "light.kitchen_lights"}, blocking=True)
hass.states.get("light.kitchen_lights").state
PYOn a real instance, install via HACS and add Developer Shell for Home Assistant from Settings → Devices & services → Add integration (or add dev_shell_server: to configuration.yaml, which is imported as a config entry), then set HASS_URL and HASS_TOKEN (an admin long-lived token).
Tests: uv run pytest covers the engine without needing HA.