Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 23 additions & 4 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,13 +1,32 @@
# Docker Compose defaults. Copy this file to .env and set a long, private API
# token. The supplied Compose file keeps the API inside its Docker network.
# Docker Compose defaults. Copy this file to .env, then set a long, private API
# token. Home Assistant app users set the equivalent values in the app's
# Configuration tab instead. The supplied Compose file keeps the API inside
# its Docker network; the integration must be able to reach this address.
#
# Listen address and port. Keep HOST as 0.0.0.0 in the container so Home
# Assistant can connect. PORT is also the port used in the integration URL.
VIRTUAL_CARILLON_HOST=0.0.0.0
VIRTUAL_CARILLON_PORT=9876

# Persistent runtime data: the SQLite schedule/history, imported recordings,
# LitCal cache, and rendered audio cache. Do not point this at source control.
VIRTUAL_CARILLON_DATA_DIR=/app/.data

# Bearer token for every /api/* request. /health remains public for health
# checks. Set this before allowing anything beyond a trusted local network.
VIRTUAL_CARILLON_API_TOKEN=

# Default acoustic character for generated bells and hymns. Valid profiles are
# near, church-grounds, quarter-mile, half-mile, and one-mile. Home Assistant
# schedules can choose the same profiles in the integration settings.
VIRTUAL_CARILLON_DISTANCE_PROFILE=half-mile

# Generated WAV sample rate. Valid values are 44100 and 48000 Hz.
VIRTUAL_CARILLON_SAMPLE_RATE=44100

# LitCal connection defaults. Automatic Home Assistant routines always use
# LitCal; each Home Assistant schedule stores its selected calendar.
# LitCal connection. The URL should point to a compatible Liturgical Calendar
# API. The calendar here is the default for CLI/API requests; each Home
# Assistant schedule stores its own calendar choice in the integration.
VIRTUAL_CARILLON_LITCAL_URL=https://litcal.johnromanodorazio.com/api/v5
# Valid calendars: general, US, IT, NL, VA, or CA.
VIRTUAL_CARILLON_LITCAL_CALENDAR=general
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ jobs:
run: pnpm release:check

- name: Validate Home Assistant integration syntax
run: python3 -m compileall -q custom_components/virtual_carillon
run: python3 -m compileall -q homeassistant/integration

- name: Validate JSON metadata
run: |
python3 -m json.tool custom_components/virtual_carillon/manifest.json >/dev/null
python3 -m json.tool homeassistant/integration/manifest.json >/dev/null
python3 -m json.tool hacs.json >/dev/null

container:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/publish-app.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ jobs:
run: pnpm release:check -- "${RELEASE_VERSION#v}"

- name: Validate Home Assistant integration syntax
run: python3 -m compileall -q custom_components/virtual_carillon
run: python3 -m compileall -q homeassistant/integration

- name: Log in to GHCR
uses: docker/login-action@v3
Expand Down
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# Changelog

## 0.1.0-beta.2

Follow-up beta release containing the polish and cleanup that missed the initial beta.

- Updated the Virtual Carillon logo and Home Assistant app branding.
- Reorganized the engine, Home Assistant integration, and documentation for clearer ownership and maintenance.
- Cleaned up and expanded project documentation and contributor guidance.
- Applied minor code-quality, build, CI, and release-process improvements.

## 0.1.0-beta.1

First public beta release.
Expand Down
8 changes: 4 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Thank you for helping improve Virtual Carillon. Contributions should preserve a

## Before you begin

Read the [development guide](doc/development.md) for setup, checks, deployment helpers, and releases. The [architecture guide](doc/architecture.md) explains the project boundaries, and the [testing guide](doc/testing.md) describes the expected smoke tests.
Read the [development guide](docs/development.md) for setup, architecture, checks, testing, deployment helpers, and releases.

For a bug, include the deployment method, the relevant date and calendar when liturgical selection is involved, steps to reproduce, and the useful portion of the logs. Remove API tokens, private URLs, personal information, and private recordings before posting.

Expand Down Expand Up @@ -57,15 +57,15 @@ 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 `custom_components/virtual_carillon` directory over SSH, restarts the target Home Assistant 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 `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.

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.

`scripts/reset-daily.sh` is another deployment helper. It clears Automatic-hymn history for today or a supplied date on the hosted engine. It is useful when testing selection repeatedly, but it changes persistent runtime state and should not be used casually on a shared installation.

## Releases

Release versions must agree in `package.json`, `custom_components/virtual_carillon/manifest.json`, `homeassistant/app/config.yaml`, and `Dockerfile`. Run:
Release versions must agree in `package.json`, `homeassistant/integration/manifest.json`, `homeassistant/app/config.yaml`, and `Dockerfile`. Run:

```bash
pnpm release:check
Expand All @@ -91,4 +91,4 @@ git status
git diff --check
```

Do not commit `.env` or `dev.env` files, credentials, runtime data, private recordings, generated audio, `dist/`, `node_modules/`, Python bytecode, coverage output, or editor files. Keep test data disposable and avoid placing personal deployment details in examples.
Do not commit `.env` or `dev.env` files, credentials, runtime data, private recordings, generated audio, `engine/dist/`, `node_modules/`, Python bytecode, coverage output, or editor files. Keep test data disposable and avoid placing personal deployment details in examples.
32 changes: 17 additions & 15 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,10 @@ COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile
COPY tsconfig.json eslint.config.mjs .prettierrc.json ./
COPY scripts ./scripts
COPY src ./src
COPY engine/src ./engine/src
RUN pnpm build

FROM node:24-bookworm-slim AS runtime
ARG BUILD_VERSION=0.1.0-beta.1
ARG BUILD_ARCH=amd64
LABEL \
io.hass.version="${BUILD_VERSION}" \
io.hass.type="app" \
io.hass.arch="aarch64|amd64" \
org.opencontainers.image.title="Virtual Carillon" \
org.opencontainers.image.source="https://github.com/HPaulson/virtual-carillon" \
org.opencontainers.image.licenses="MIT"
FROM node:24-bookworm-slim AS runtime-deps
ENV NODE_ENV=production \
VIRTUAL_CARILLON_HOST=0.0.0.0 \
VIRTUAL_CARILLON_PORT=9876 \
Expand All @@ -30,13 +21,24 @@ RUN apt-get update \
RUN corepack enable
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --prod --frozen-lockfile
COPY --from=build /app/dist ./dist
COPY bin ./bin

FROM runtime-deps AS runtime
ARG BUILD_VERSION=0.1.0-beta.2
ARG BUILD_ARCH=amd64
LABEL \
io.hass.version="${BUILD_VERSION}" \
io.hass.type="app" \
io.hass.arch="aarch64|amd64" \
org.opencontainers.image.title="Virtual Carillon" \
org.opencontainers.image.source="https://github.com/HPaulson/virtual-carillon" \
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 ./bin/virtual-carillon-app-entrypoint.mjs
COPY homeassistant/app/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 \
CMD node -e "fetch('http://127.0.0.1:9876/health').then(r => process.exit(r.ok ? 0 : 1)).catch(() => process.exit(1))"
CMD ["node", "bin/virtual-carillon-app-entrypoint.mjs"]
CMD ["node", "engine/bin/virtual-carillon-app-entrypoint.mjs"]
42 changes: 22 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Virtual Carillon

<p align="center">
<img src="assets/virtual-carillon-logo.svg" alt="Virtual Carillon" width="480">
<img src="homeassistant/app/logo.png" alt="Virtual Carillon" width="480">
</p>

Virtual Carillon turns your speakers into a programmable carillon. Play a bell, signal, or liturgically-appropriate Catholic hymn whenever you like.
Virtual Carillon turns your speakers into a programmable Church carillon.

Use it with Home Assistant to build routines such as:

Expand All @@ -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 an optional community store inside Home Assistant that we recommend for most users. It makes the Virtual Carillon integration easy to install, but it is not required if you prefer to copy the integration files manually.
[HACS](https://hacs.xyz/docs/use/) (Home Assistant Community Store) is an optional community store inside Home Assistant. This repository keeps all Home Assistant sources under `homeassistant/`; use the manual installation path below unless a HACS release package is provided.

For either Home Assistant path, you must have at least one working Home Assistant `media_player` (speaker) before setting up Virtual Carillon.

Expand All @@ -42,8 +42,7 @@ Use this path when your Home Assistant installation has **Settings → Apps**. I
3. Open the app’s **Configuration** tab. Set **API token** to a long, unique private value, choose **Save**, and restart the app if Home Assistant asks.
4. Install the integration:

- **With HACS (Recommended):** open **HACS → Integrations**. Open the three-dot menu, choose **Custom repositories**, add `https://github.com/HPaulson/virtual-carillon` with category **Integration**, then choose **Add**. Search HACS for **Virtual Carillon**, open it, and choose **Download**. Restart Home Assistant when the download finishes.
- **Without HACS:** copy this repository’s `custom_components/virtual_carillon` directory to `/config/custom_components/virtual_carillon/`, then restart Home Assistant.
- **Manual installation:** copy this repository’s `homeassistant/integration` directory to `/config/custom_components/virtual_carillon/`, then restart Home Assistant.

5. Open **Settings → Devices & services → Add integration**, search for **Virtual Carillon**, and enter:

Expand Down Expand Up @@ -81,7 +80,7 @@ Use this path when Home Assistant itself runs in a Docker container. Virtual Car

The `virtual-carillon_default` network is created by the command in step 3. Once both containers share it, Home Assistant can reach the engine as `http://virtual-carillon:9876`. Keep this connection in your own Compose configuration if you recreate the Home Assistant container.

5. In the Home Assistant web interface, install the integration through HACS: **HACS → Integrations → three-dot menu → Custom repositories**. Add `https://github.com/HPaulson/virtual-carillon` as an **Integration**, download **Virtual Carillon**, and restart Home Assistant. Without HACS, copy `custom_components/virtual_carillon` to `/config/custom_components/virtual_carillon/` and restart instead.
5. Copy this repository’s `homeassistant/integration` directory to `/config/custom_components/virtual_carillon/`, then restart Home Assistant. HACS custom repositories currently require the integration under a repository-root `custom_components/` directory, so this source layout is intentionally installed manually.
6. Open **Settings → Devices & services → Add integration**, search for **Virtual Carillon**, and enter:

- **Engine URL:** `http://virtual-carillon:9876`
Expand All @@ -94,7 +93,7 @@ Do not run the Home Assistant app and the Compose service against the same port

### 3. Standalone engine (advanced)

Use this path only when you are comfortable working with the command line without a GUI to interact with the Virtual Carillon. It can play the host’s default audio output, but local speakers, Bluetooth, and unusual audio setups are outside the project’s supported deployment paths. The CLI and [HTTP API](doc/api.md) are provided for experienced users to integrate as they see fit.
Use this path only when you are comfortable working with the command line without a GUI to interact with the Virtual Carillon. It can play the host’s default audio output, but local speakers, Bluetooth, and unusual audio setups are outside the project’s supported deployment paths. The CLI and [HTTP API](docs/api.md) are provided for experienced users to integrate as they see fit.

Install Node.js 24 or later and the pnpm version declared in `package.json`, then run:

Expand All @@ -103,18 +102,18 @@ pnpm install --frozen-lockfile
pnpm build

# List the available bells, signals, and hymns.
node dist/cli/index.js assets
node engine/dist/cli/index.js assets

# Check whether this host has an available local audio output.
node dist/cli/index.js doctor
node dist/cli/index.js devices
node engine/dist/cli/index.js doctor
node engine/dist/cli/index.js devices

# Play through the default local output.
node dist/cli/index.js play test-bell
node dist/cli/index.js play angelus
node engine/dist/cli/index.js play test-bell
node engine/dist/cli/index.js play angelus
```

To expose the API on the local machine, run `node dist/cli/index.js server`. Set `VIRTUAL_CARILLON_API_TOKEN` before binding it to any network address. Run `node dist/cli/index.js --help` for the complete command reference.
To expose the API on the local machine, run `node engine/dist/cli/index.js server`. Set `VIRTUAL_CARILLON_API_TOKEN` before binding it to any network address. Run `node engine/dist/cli/index.js --help` for the complete command reference.

## Scheduling in Home Assistant

Expand All @@ -129,11 +128,11 @@ The editor has one Westminster schedule and three routine modes:
| **Category — Select from a hymn category** | Variety within a chosen category, such as Marian or Eucharistic. |
| **Automatic — Hymn selected based on liturgical calendar** | A hymn chosen from the current LitCal context, with an optional Liturgy of the Hours preference. |

Automatic mode uses the selected LitCal calendar, favoring the day’s feast, saint, category, and season while avoiding a suitable hymn already used that day. See the [automatic mode guide](doc/automatic-mode.md) for details on the hymn selection behavior.
Automatic mode uses the selected LitCal calendar, favoring the day’s feast, saint, category, and season while avoiding a suitable hymn already used that day. See the [automatic mode guide](docs/automatic-mode.md) for details on the hymn selection behavior.

Use the built-in editor for simple, repetitive schedules with fixed times, days, and media players. When a schedule depends on other Home Assistant entities, use a regular automation and select a Virtual Carillon item from the Media browser. The engine renders and serves the audio and keeps it available in Home Assistant’s media library; Home Assistant chooses the media players and handles those additional conditions.

The [Home Assistant guide](doc/home-assistant.md#create-schedules) documents every schedule field, cadence, time-window rule, category, canonical-hour preference, and volume behavior in the GUI.
The [Home Assistant guide](docs/home-assistant.md#create-schedules) documents every schedule field, cadence, time-window rule, category, canonical-hour preference, and volume behavior in the GUI.

## A few good starting points

Expand All @@ -148,11 +147,14 @@ Virtual Carillon does not set up speakers, Bluetooth pairing, or media-player in

## Further reading

- [Home Assistant setup, actions, and schedule details](doc/home-assistant.md)
- [Docker deployment](docs/docker.md)
- [Configuration reference](docs/configuration.md)
- [Adding your own recordings](doc/content.md)
- [Documentation index](doc/README.md)
The guides below expand on the relevant parts of this README:

- [Home Assistant setup, actions, and schedule details](docs/home-assistant.md)
- [Automatic hymn selection](docs/automatic-mode.md)
- [Development, architecture, and testing](docs/development.md)
- [HTTP API reference](docs/api.md)
- [Contributing guide](CONTRIBUTING.md)
- [Security policy](SECURITY.md)

## License

Expand Down
1 change: 0 additions & 1 deletion assets/virtual-carillon-icon.svg

This file was deleted.

1 change: 0 additions & 1 deletion assets/virtual-carillon-logo.svg

This file was deleted.

Loading
Loading