diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 15c4d5a..30e9505 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,11 +43,11 @@ jobs: run: pnpm release:check - name: Validate Home Assistant integration syntax - run: python3 -m compileall -q homeassistant/integration + run: python3 -m compileall -q custom_components/virtual_carillon - name: Validate JSON metadata run: | - python3 -m json.tool homeassistant/integration/manifest.json >/dev/null + python3 -m json.tool custom_components/virtual_carillon/manifest.json >/dev/null python3 -m json.tool hacs.json >/dev/null container: diff --git a/.github/workflows/publish-app.yml b/.github/workflows/publish-app.yml index 731b3c5..52af076 100644 --- a/.github/workflows/publish-app.yml +++ b/.github/workflows/publish-app.yml @@ -61,11 +61,11 @@ jobs: run: pnpm release:check -- "${RELEASE_VERSION#v}" - name: Validate Home Assistant integration syntax - run: python3 -m compileall -q homeassistant/integration + run: python3 -m compileall -q custom_components/virtual_carillon - name: Package HACS integration release run: | - cd homeassistant/integration + cd custom_components/virtual_carillon zip -r ../../virtual_carillon.zip . -x '__pycache__/*' '*.pyc' - name: Publish GitHub release with HACS asset diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e7ad9a5..b62cd75 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -57,7 +57,7 @@ Run the same combined checks locally with `pnpm ci:check` before requesting revi ## Development deployment helper -`scripts/push-live.sh` is available for testing Home Assistant integration changes on a configured remote Docker installation. It type-checks the project, copies the current working tree’s `homeassistant/integration` directory into the target Home Assistant container’s `/config/custom_components/virtual_carillon` location over SSH, restarts the container, and waits for it to become healthy. +`scripts/push-live.sh` is available for testing Home Assistant integration changes on a configured remote Docker installation. It type-checks the project, copies the current working tree’s `custom_components/virtual_carillon` directory into the target Home Assistant container’s `/config/custom_components/virtual_carillon` location over SSH, restarts the container, and waits for it to become healthy. It reads `REMOTE_HOST` and `HA_CONTAINER` from a local ignored `dev.env` file. This is a development convenience, not a substitute for CI or the release process. Check the current branch, working tree, remote host, and target container before running it. It does not deploy the engine container or publish a release. @@ -65,7 +65,7 @@ It reads `REMOTE_HOST` and `HA_CONTAINER` from a local ignored `dev.env` file. T ## Releases -Release versions must agree in `package.json`, `homeassistant/integration/manifest.json`, `homeassistant/app/config.yaml`, and `Dockerfile`. Run: +Release versions must agree in `package.json`, `custom_components/virtual_carillon/manifest.json`, `add-on/config.yaml`, and `Dockerfile`. Run: ```bash pnpm release:check diff --git a/Dockerfile b/Dockerfile index c4b4f62..baf2ac9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -23,7 +23,7 @@ COPY package.json pnpm-lock.yaml ./ RUN pnpm install --prod --frozen-lockfile FROM runtime-deps AS runtime -ARG BUILD_VERSION=0.1.0-beta.2 +ARG BUILD_VERSION=0.1.0-beta.3 ARG BUILD_ARCH=amd64 LABEL \ io.hass.version="${BUILD_VERSION}" \ @@ -34,9 +34,8 @@ LABEL \ org.opencontainers.image.licenses="MIT" COPY --from=build /app/engine/dist ./engine/dist COPY engine/bin ./engine/bin -COPY homeassistant ./homeassistant COPY README.md LICENSE ./ -COPY homeassistant/app/entrypoint.mjs ./engine/bin/virtual-carillon-app-entrypoint.mjs +COPY add-on/entrypoint.mjs ./engine/bin/virtual-carillon-app-entrypoint.mjs RUN mkdir -p /app/.data/cache EXPOSE 9876 HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \ diff --git a/README.md b/README.md index 18ddc16..aaf00c8 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Virtual Carillon

- Virtual Carillon + Virtual Carillon

Virtual Carillon turns your speakers into a programmable Church carillon. @@ -20,7 +20,7 @@ You can also run the carillon on its own from the command line or connect to it Most people will use Virtual Carillon with [Home Assistant](https://www.home-assistant.io/getting-started/), a free, self-hosted home-automation system. The included Home Assistant Integration provides a user-friendly GUI to interact with Virtual Carillon. We also provide Virtual Carillon as a standalone app for advanced users who are comfortable working from the command line and don't want to use Home Assistant. -[HACS](https://hacs.xyz/docs/use/) (Home Assistant Community Store) is the recommended way to install the Home Assistant integration. Releases include the HACS package; the repository keeps its source under `homeassistant/integration` so no HACS-specific top-level source directory is needed. If HACS is unavailable, use the manual installation fallback below. +[HACS](https://hacs.xyz/docs/use/) (Home Assistant Community Store) is the recommended way to install the Home Assistant integration. The integration is stored in the standard top-level `custom_components/virtual_carillon` directory, and releases include the HACS package. If HACS is unavailable, use the manual installation fallback below. For either Home Assistant path, you must have at least one working Home Assistant `media_player` (speaker) before setting up Virtual Carillon. @@ -46,7 +46,7 @@ Use this path when your Home Assistant installation has **Settings → Apps**. I - Add `https://github.com/HPaulson/virtual-carillon` as an **Integration**, then choose **Download** for the latest release. - Restart Home Assistant when HACS asks. - If HACS is unavailable, manually copy this repository’s `homeassistant/integration` directory to `/config/custom_components/virtual_carillon/`, then restart Home Assistant. + If HACS is unavailable, manually copy this repository’s `custom_components/virtual_carillon` directory to `/config/custom_components/virtual_carillon/`, then restart Home Assistant. 5. Open **Settings → Devices & services → Add integration**, search for **Virtual Carillon**, and enter: @@ -90,7 +90,7 @@ Use this path when Home Assistant itself runs in a Docker container. Virtual Car - Add `https://github.com/HPaulson/virtual-carillon` as an **Integration**, then choose **Download** for the latest release. - Restart Home Assistant when HACS asks. - If HACS is unavailable, manually copy this repository’s `homeassistant/integration` directory to `/config/custom_components/virtual_carillon/`, then restart Home Assistant. + If HACS is unavailable, manually copy this repository’s `custom_components/virtual_carillon` directory to `/config/custom_components/virtual_carillon/`, then restart Home Assistant. 6. Open **Settings → Devices & services → Add integration**, search for **Virtual Carillon**, and enter: diff --git a/homeassistant/app/DOCS.md b/add-on/DOCS.md similarity index 100% rename from homeassistant/app/DOCS.md rename to add-on/DOCS.md diff --git a/homeassistant/app/config.yaml b/add-on/config.yaml similarity index 97% rename from homeassistant/app/config.yaml rename to add-on/config.yaml index 347fa81..0b5f6b7 100644 --- a/homeassistant/app/config.yaml +++ b/add-on/config.yaml @@ -1,5 +1,5 @@ name: Virtual Carillon -version: 0.1.0-beta.2 +version: 0.1.0-beta.3 slug: virtual_carillon description: Virtual Carillon turns your speakers into a programmable carillon. Play Westminster Chimes, the Angelus, and liturgically-appropriate Catholic hymns. url: https://github.com/HPaulson/virtual-carillon diff --git a/homeassistant/app/entrypoint.mjs b/add-on/entrypoint.mjs similarity index 100% rename from homeassistant/app/entrypoint.mjs rename to add-on/entrypoint.mjs diff --git a/homeassistant/app/icon.png b/add-on/icon.png similarity index 100% rename from homeassistant/app/icon.png rename to add-on/icon.png diff --git a/homeassistant/app/logo.png b/add-on/logo.png similarity index 100% rename from homeassistant/app/logo.png rename to add-on/logo.png diff --git a/homeassistant/app/translations/en.yaml b/add-on/translations/en.yaml similarity index 100% rename from homeassistant/app/translations/en.yaml rename to add-on/translations/en.yaml diff --git a/homeassistant/integration/__init__.py b/custom_components/virtual_carillon/__init__.py similarity index 100% rename from homeassistant/integration/__init__.py rename to custom_components/virtual_carillon/__init__.py diff --git a/homeassistant/integration/brand/icon.png b/custom_components/virtual_carillon/brand/icon.png similarity index 100% rename from homeassistant/integration/brand/icon.png rename to custom_components/virtual_carillon/brand/icon.png diff --git a/homeassistant/integration/brand/icon@2x.png b/custom_components/virtual_carillon/brand/icon@2x.png similarity index 100% rename from homeassistant/integration/brand/icon@2x.png rename to custom_components/virtual_carillon/brand/icon@2x.png diff --git a/homeassistant/integration/brand/logo.png b/custom_components/virtual_carillon/brand/logo.png similarity index 100% rename from homeassistant/integration/brand/logo.png rename to custom_components/virtual_carillon/brand/logo.png diff --git a/homeassistant/integration/brand/logo@2x.png b/custom_components/virtual_carillon/brand/logo@2x.png similarity index 100% rename from homeassistant/integration/brand/logo@2x.png rename to custom_components/virtual_carillon/brand/logo@2x.png diff --git a/homeassistant/integration/config_flow.py b/custom_components/virtual_carillon/config_flow.py similarity index 100% rename from homeassistant/integration/config_flow.py rename to custom_components/virtual_carillon/config_flow.py diff --git a/homeassistant/integration/const.py b/custom_components/virtual_carillon/const.py similarity index 100% rename from homeassistant/integration/const.py rename to custom_components/virtual_carillon/const.py diff --git a/homeassistant/integration/coordinator.py b/custom_components/virtual_carillon/coordinator.py similarity index 100% rename from homeassistant/integration/coordinator.py rename to custom_components/virtual_carillon/coordinator.py diff --git a/homeassistant/integration/manifest.json b/custom_components/virtual_carillon/manifest.json similarity index 91% rename from homeassistant/integration/manifest.json rename to custom_components/virtual_carillon/manifest.json index c8215b4..5b1d777 100644 --- a/homeassistant/integration/manifest.json +++ b/custom_components/virtual_carillon/manifest.json @@ -1,7 +1,7 @@ { "domain": "virtual_carillon", "name": "Virtual Carillon", - "version": "0.1.0-beta.2", + "version": "0.1.0-beta.3", "documentation": "https://github.com/HPaulson/virtual-carillon", "issue_tracker": "https://github.com/HPaulson/virtual-carillon/issues", "codeowners": [], diff --git a/homeassistant/integration/media_source.py b/custom_components/virtual_carillon/media_source.py similarity index 100% rename from homeassistant/integration/media_source.py rename to custom_components/virtual_carillon/media_source.py diff --git a/homeassistant/integration/schedule_runner.py b/custom_components/virtual_carillon/schedule_runner.py similarity index 100% rename from homeassistant/integration/schedule_runner.py rename to custom_components/virtual_carillon/schedule_runner.py diff --git a/homeassistant/integration/sensor.py b/custom_components/virtual_carillon/sensor.py similarity index 100% rename from homeassistant/integration/sensor.py rename to custom_components/virtual_carillon/sensor.py diff --git a/homeassistant/integration/services.yaml b/custom_components/virtual_carillon/services.yaml similarity index 100% rename from homeassistant/integration/services.yaml rename to custom_components/virtual_carillon/services.yaml diff --git a/homeassistant/integration/strings.json b/custom_components/virtual_carillon/strings.json similarity index 100% rename from homeassistant/integration/strings.json rename to custom_components/virtual_carillon/strings.json diff --git a/homeassistant/integration/translations/en.json b/custom_components/virtual_carillon/translations/en.json similarity index 100% rename from homeassistant/integration/translations/en.json rename to custom_components/virtual_carillon/translations/en.json diff --git a/docs/development.md b/docs/development.md index f58a5cf..0a51cec 100644 --- a/docs/development.md +++ b/docs/development.md @@ -100,7 +100,7 @@ node engine/dist/cli/index.js schedule show ### `scripts/push-live.sh` -This script deploys the current working tree’s engine and Home Assistant integration to a remote Docker-based installation. It runs pnpm typecheck, archives `homeassistant/integration`, installs it into Home Assistant’s runtime `/config/custom_components/virtual_carillon` location, builds the engine image on the remote host for its architecture, and force-recreates the engine through its existing Compose project. It then restarts Home Assistant and waits for the Home Assistant health check. The engine’s persistent data volume is preserved and not modified. This is useful for live-testing the integration, though a local Home Assistant instance may also be used. The first run may take several minutes because the image installs FFmpeg and its dependencies. +This script deploys the current working tree’s engine and Home Assistant integration to a remote Docker-based installation. It runs pnpm typecheck, archives `custom_components/virtual_carillon`, installs it into Home Assistant’s runtime `/config/custom_components/virtual_carillon` location, builds the engine image on the remote host for its architecture, and force-recreates the engine through its existing Compose project. It then restarts Home Assistant and waits for the Home Assistant health check. The engine’s persistent data volume is preserved and not modified. This is useful for live-testing the integration, though a local Home Assistant instance may also be used. The first run may take several minutes because the image installs FFmpeg and its dependencies. Create a local, ignored `dev.env` with at least: @@ -168,8 +168,8 @@ Keep the major boundaries intact: audio synthesis, the asset library, persistenc The project version is duplicated intentionally for the package, Home Assistant integration, Home Assistant app, and container metadata. These values must agree in: - `package.json` (`version`); -- `homeassistant/integration/manifest.json` (`version`); -- `homeassistant/app/config.yaml` (`version`); and +- `custom_components/virtual_carillon/manifest.json` (`version`); +- `add-on/config.yaml` (`version`); and - `Dockerfile` (`ARG BUILD_VERSION`). Check them with: @@ -218,8 +218,8 @@ The standard Home Assistant path is speaker-agnostic. The integration turns a re | `engine/src/library/` | Bundled assets, imported recordings, hymn catalog, metadata, and rendering. | | `engine/src/liturgical/` | LitCal retrieval and caching, taxonomy, conditions, and hymn queries. | | `engine/src/scheduling/` and `engine/src/database/` | Schedule validation, matching, claims, events, and completed-hymn history. | -| `homeassistant/integration/` | Config flow, schedule runner, media source, services, sensor, and branding. | -| `homeassistant/app/` | Home Assistant Supervisor app definition and entrypoint. | +| `custom_components/virtual_carillon/` | Config flow, schedule runner, media source, services, sensor, and branding. | +| `add-on/` | Home Assistant Supervisor app definition and entrypoint. | Schedules with Home Assistant `mediaPlayers` are claimed by the integration. Schedules with native `outputs`, or no target list, are evaluated by the engine’s native timer. Claims use the local date, minute, and schedule revision to avoid duplicate delivery after restarts. diff --git a/package.json b/package.json index d9bb234..f92ccf5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "virtual-carillon", - "version": "0.1.0-beta.2", + "version": "0.1.0-beta.3", "description": "A virtual carillon with Catholic bells, hymn arrangements, and Home Assistant integration.", "license": "MIT", "repository": { @@ -26,7 +26,7 @@ "files": [ "engine/dist", "engine/bin", - "homeassistant", + "add-on", "README.md", "LICENSE" ], diff --git a/scripts/check-ci.mjs b/scripts/check-ci.mjs index 464667a..d90d8e1 100644 --- a/scripts/check-ci.mjs +++ b/scripts/check-ci.mjs @@ -30,8 +30,8 @@ async function check(label, callback) { } function checkPythonMetadata() { - run('python3', ['-m', 'compileall', '-q', 'homeassistant/integration']); - run('python3', ['-m', 'json.tool', 'homeassistant/integration/manifest.json']); + run('python3', ['-m', 'compileall', '-q', 'custom_components/virtual_carillon']); + run('python3', ['-m', 'json.tool', 'custom_components/virtual_carillon/manifest.json']); run('python3', ['-m', 'json.tool', 'hacs.json']); } diff --git a/scripts/check-release.mjs b/scripts/check-release.mjs index 9710de0..86651d7 100644 --- a/scripts/check-release.mjs +++ b/scripts/check-release.mjs @@ -13,12 +13,14 @@ if (packageJson.version !== expectedVersion) { failures.push(`package.json is ${packageJson.version}, expected ${expectedVersion}`); } -const manifest = JSON.parse(await readFile('homeassistant/integration/manifest.json', 'utf8')); +const manifest = JSON.parse( + await readFile('custom_components/virtual_carillon/manifest.json', 'utf8'), +); if (manifest.version !== expectedVersion) { failures.push(`Home Assistant manifest is ${manifest.version}, expected ${expectedVersion}`); } -const appConfig = await readFile('homeassistant/app/config.yaml', 'utf8'); +const appConfig = await readFile('add-on/config.yaml', 'utf8'); if (!new RegExp(`^version: ${expectedVersion.replaceAll('.', '\\.')}$`, 'm').test(appConfig)) { failures.push(`Home Assistant app config does not declare ${expectedVersion}`); } diff --git a/scripts/push-live.sh b/scripts/push-live.sh index 982c922..c005f3d 100755 --- a/scripts/push-live.sh +++ b/scripts/push-live.sh @@ -44,7 +44,7 @@ COPYFILE_DISABLE=1 tar \ --exclude='__pycache__' \ --exclude='**/*.pyc' \ -czf "$LOCAL_ARCHIVE" \ - -C "$ROOT_DIR/homeassistant/integration" \ + -C "$ROOT_DIR/custom_components/virtual_carillon" \ . scp "$LOCAL_ARCHIVE" "$REMOTE_HOST:$REMOTE_ARCHIVE" ssh "$REMOTE_HOST" "docker cp '$REMOTE_ARCHIVE' '$HA_CONTAINER:/tmp/virtual-carillon-ha.tar.gz'" @@ -67,7 +67,7 @@ COPYFILE_DISABLE=1 tar \ --exclude='*.sqlite-wal' \ -czf "$ENGINE_ARCHIVE" \ -C "$ROOT_DIR" \ - Dockerfile package.json pnpm-lock.yaml tsconfig.json eslint.config.mjs .prettierrc.json scripts engine homeassistant README.md LICENSE + Dockerfile package.json pnpm-lock.yaml tsconfig.json eslint.config.mjs .prettierrc.json scripts engine add-on README.md LICENSE scp "$ENGINE_ARCHIVE" "$REMOTE_HOST:$REMOTE_ENGINE_ARCHIVE" echo "==> Rebuilding and restarting the Virtual Carillon engine"