Skip to content

Run Dapple as a Home Assistant add-on (0.6.0) - #22

Merged
andrewfraley merged 8 commits into
mainfrom
home-assistant-addon
Sep 26, 2026
Merged

andrewfraley merged 8 commits into
mainfrom
home-assistant-addon

Conversation

@andrewfraley

@andrewfraley andrewfraley commented Sep 26, 2026 •

Copy link
Copy Markdown
Owner

Dapple can now be installed from Home Assistant's App store on Home Assistant OS, and opens in the sidebar. Released as 0.6.0.

What's in it

  • Add-on repository. repository.yaml plus home-assistant/dapple/: a config.yaml that runs the published afraley/dapple:<version> image (no separate build), with DOCS.md, a store blurb and an icon. Validated against the Supervisor's own SCHEMA_APP_CONFIG.
  • Sidebar via ingress. The UI uses relative paths now (api/..., favicon.svg, Vite base: './'), so it works under /api/hassio_ingress/<token>/. Nothing changes standalone: routing is by #hash, so the page always loads from /.
  • MQTT auto-fill. With services: [mqtt:want], sync_mqtt in app/supervisor.py asks the Supervisor for Mosquitto's address and login on every start:
    • No broker saved yet: it saves Mosquitto's, switched off.
    • The saved broker has the same host, port and username as Mosquitto's: it takes Mosquitto's current password. Reinstalling Mosquitto issues a new one the user never sees. Nothing else changes, and the switch stays as the user left it.
    • Any other broker belongs to the user and is never touched.
    • It does nothing outside an add-on (no SUPERVISOR_TOKEN).
  • No host port by default (8080/tcp: null), so it can't clash with another add-on on 8080. It can be turned on in the add-on's Network tab. From Home Assistant, rest_command reaches it by hostname.
  • stable branch. The Supervisor reads the add-on from git, so reading main would offer 0.6.0 minutes before its image exists. Users add …/dapple#stable, and the release job moves it:
    • It runs after the image is pushed and the GitHub release exists.
    • It pushes with the STABLE_DEPLOY_KEY deploy key from a release environment that only main can use. The workflow's own token may not push a commit that changes .github/workflows/, and this one does.
    • The release step skips an existing release, so if moving stable fails, a re-run finishes the job.
    • It's a fast-forward-only git push, and stable is excluded from branch builds.
    • CI checks that the add-on's version matches pyproject.toml.
  • The example config moved from data.example/config.yaml to docs/example-config.yaml. The Supervisor treats every config.yaml in the repo as an add-on and would have warned about it on every store reload.
  • Docs: README (On Home Assistant OS, with a one-click link), HOME_ASSISTANT.md, DEVELOPING.md and CLAUDE.md.

Already set up with gh

  • The stable branch exists at v0.5.1 (164164f). Creating it started a build on stable under the old workflow, which I cancelled before it pushed an image.
  • Deploy key "Release job: move stable" (write access). Its private half exists only as the STABLE_DEPLOY_KEY secret in the new release environment, which is limited to main. A dry-run push to stable with it authenticated, and the move was a fast-forward.
  • "Protect stable" ruleset (24044769), with no bypass: no deletion, no force pushes, signed commits only, and test and image must have passed.
  • "Only the release job moves stable" ruleset (24045227): only a deploy key may update stable. GitHub refused a GitHub Actions exemption, since that's only allowed on organization repos, but a deploy-key exemption works on personal repos. It lives in its own ruleset so the key doesn't also get past the rules above.

Tested

  • 341 Python tests, including 11 new ones in tests/test_supervisor.py. Frontend tests and the format checks pass.
  • Built UI behind an nginx proxy at /api/hassio_ingress/test/, in headless Chromium: the page, assets and every API call load under the prefix. At /, all the same files load too.
  • Built image run the way the Supervisor runs it (root, fresh root-owned /data, SUPERVISOR_TOKEN, a fake supervisor host answering /services/mqtt): the broker was filled in with enabled: false and the password not returned by GET. /data files end up owned by 1000, and a restart doesn't fill it in again.

Still to check on a real Home Assistant OS box

  • Install it as a local add-on with version: home-assistant-addon (steps in DEVELOPING.md): open it from the sidebar, check the pre-filled Mosquitto login connects, and check the add-on can reach the strands.
  • Confirm Home Assistant resolves the add-on's hostname (<hash>-dapple:8080) for rest_command.
  • After merge: the release job is green, and gh api repos/andrewfraley/dapple/branches/stable --jq .commit.sha equals the merge commit. That merge is the first real run of the deploy-key push against the rulesets; the dry run can't check rules.

🤖 Generated with Claude Code

andrewfraley and others added 8 commits September 26, 2026 12:12
Home Assistant's ingress serves an add-on at /api/hassio_ingress/<token>/,
where absolute /api and /favicon paths miss. Standalone is unchanged: the
page always loads from / (routing is hash-based), so api/ping is /api/ping.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Under the Supervisor, ask /services/mqtt for the Mosquitto add-on's address
and login and save them on the Home Assistant tab, switched off. Only when no
broker is set up yet, so a user's own settings are never overwritten.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
repository.yaml makes this repo an add-on repository; home-assistant/dapple
runs the published afraley/dapple image under the Supervisor, in the
sidebar via ingress, with Mosquitto's login offered through mqtt:want.

The Supervisor treats every config.* file in the repo as an add-on and warns
about the ones that don't validate, so the example config moves to
docs/example-config.yaml.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The Supervisor reads the add-on from the repo, so a version bump on main
would reach Home Assistant minutes before its image is on Docker Hub. The
release job now moves `stable` to the released commit once the image is
pushed, and CI checks the add-on's version matches pyproject.toml.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
README gets an "On Home Assistant OS" install with the one-click repository
link; HOME_ASSISTANT.md covers the pre-filled broker and reaching the app by
hostname from rest_command; DEVELOPING.md covers the add-on, ingress and the
stable branch.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Reinstalling Mosquitto issues Dapple a new password, which the user never
sees and so can't type in. On every start, while the saved broker's host,
port and username are still the ones the Supervisor offers, take its current
password. Anything else about the broker stays the user's, and a broker they
set up themselves is still never touched.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The workflow's own token may not push a commit that changes
.github/workflows/, and moving stable to the 0.6.0 merge does, so the step
would have failed with the image published but no tag or release. The
release job now creates the release first (skipping it if it exists, so a
re-run can finish) and then pushes stable with STABLE_DEPLOY_KEY from the
main-only `release` environment.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@andrewfraley
andrewfraley merged commit 86d3ee4 into main Sep 26, 2026
6 checks passed
@andrewfraley
andrewfraley deleted the home-assistant-addon branch September 26, 2026 16:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant