Skip to main content

Blustream

Open-source toolkit for controlling Blustream audio devices — starting with the DMP168 digital audio matrix processor — across three home-automation surfaces.

Components

This repository is a monorepo housing three deliverables that share a single protocol contract under spec/:

  1. Python library + CLI (blustream/). A clean async Python API and a blustream console script. Ships to PyPI on v* tags.
  2. Control4 driver (control4/dmp168/). A Lua driver packaged as a .c4z archive that exposes the matrix as a standard Control4 audio matrix. Ships as a GitHub release with the .c4z attached on c4-v* tags.
  3. Home Assistant integration (custom_components/blustream/). A HACS integration (domain blustream) built to the HA Integration Quality Scale Gold tier. Ships as a GitHub release on hacs-v* tags, which HACS installs from the repository tree. It depends on the published blustream PyPI library rather than re-embedding the protocol code.

The protocol primitives shared between the library and the driver are generated from spec/protocol.yaml via the codegen tooling under spec/codegen/. The Python and Lua emitters write into blustream/devices/dmp168/_generated.py and control4/dmp168/src/generated.lua respectively, and CI fails when those committed files drift from what the spec would produce.

Independent versioning

Each component releases on its own cadence using a distinct tag prefix. The prefixes are disjoint so a tag for one component cannot accidentally trigger the wrong release workflow.

Component Tag prefix Workflow Artifact
Python library v* .github/workflows/release-pypi.yml blustream on PyPI (sdist + wheel)
Control4 driver c4-v* .github/workflows/release-c4z.yml GitHub release with attached .c4z
HA integration hacs-v* .github/workflows/release-hacs.yml GitHub release; HACS installs from tree

For example, a library bug-fix release tags v0.2.1, while a driver-only update tags c4-v0.3.0. The shared spec/ directory is the coordination point when a protocol change requires both components to move in lockstep.

Installation

Python library + CLI

Once published, the library installs from PyPI:

pip install blustream

For local development from a checkout:

pip install -e ".[dev]"

Or run the CLI directly from the checkout without installing:

uvx --from . blustream --host 192.0.2.100 status

Control4 driver

Download the .c4z from the latest GitHub release tagged c4-v* and install it through Composer Pro. See docs/control4-driver-plan.md for the dealer-load workflow.

Home Assistant integration

The integration installs through HACS as a custom repository (it is not yet in the default HACS store):

  1. In HACS, open the overflow menu → Custom repositories.
  2. Add https://github.com/caidurbin/blustream with category Integration.
  3. Install Blustream Audio Matrix, then restart Home Assistant.
  4. Add it from Settings → Devices & Services (Add Integration → Blustream), or accept the DHCP/zeroconf discovery prompt.

Requires Home Assistant ≥ 2026.5.0. HACS installs the integration from the repository tree at each hacs-v* release tag; it depends on the published blustream PyPI library, which Home Assistant installs automatically.

Library Usage

import asyncio
from blustream import DMP168

async def main():
    # Connect to device
    device = DMP168(host='192.0.2.100', port=23)
    await device.connect()

    # Read status
    status = await device.get_status()
    print(f"Temperature: {status.temperature}°C")
    print(f"DSP Usage: {status.dsp_usage}%")

    # Control device
    await device.power_on()
    await device.set_output_volume(1, 75, unit='percent')
    await device.route_input_to_output(input_ch=2, output=1)

    # Context manager support
    async with DMP168(host='192.0.2.100') as device:
        status = await device.get_status()
        await device.power_on()

    # Disconnect
    await device.disconnect()

# Run the async function
asyncio.run(main())

CLI Usage

Subcommand names are derived from the command registry. Use blustream --help to list all commands and blustream <command> --help for parameter details.

Get Device Status

blustream --host 192.0.2.100 status

Power Control

blustream --host 192.0.2.100 power-on
blustream --host 192.0.2.100 power-off

Volume Control

# Set output 1 volume to 75%
blustream --host 192.0.2.100 output-volume --output 1 --level 75

# Set output 1 volume to -10 dB
blustream --host 192.0.2.100 output-volume --output 1 --level -10 --unit dB

# Increase output 1 volume by one step
blustream --host 192.0.2.100 output-volume --output 1 --increase-level

# Decrease output 1 volume by one step
blustream --host 192.0.2.100 output-volume --output 1 --decrease-level

Mute Control

# Mute output 1
blustream --host 192.0.2.100 output-mute --output 1 --mute

# Unmute output 1
blustream --host 192.0.2.100 output-mute --output 1 --no-mute

Routing

# Route input 2 to output 1
blustream --host 192.0.2.100 route --input 2 --output 1

Presets

# Save current configuration to preset 1
blustream --host 192.0.2.100 preset-save --preset 1

# Recall preset 1
blustream --host 192.0.2.100 preset-recall --preset 1

# Get preset status
blustream --host 192.0.2.100 preset-status --preset 1

JSON Output

# Get status as JSON
blustream --host 192.0.2.100 status --json

Command Line Options

Global flags must appear before the subcommand (e.g. blustream --yes reboot, not blustream reboot --yes).

  • --device: Device type (default: dmp168)
  • --host: Device hostname or IP address (default: localhost)
  • --port: TCP port (default: 23)
  • --timeout: Connection timeout in seconds (default: 5.0)
  • --verbose, -v: Enable verbose output
  • --debug: Enable debug output
  • --json: Output results as JSON
  • --yes, -y: Skip confirmations

Architecture

The library is designed with extensibility in mind:

  • Base Framework: Abstract base classes for devices and connections
  • Device Implementations: Device-specific code in separate modules
  • Command Registry: Commands are registered with metadata for introspection
  • Connection Layer: Pluggable connection implementations (TCP/IP, serial, etc.)

Supported Devices

  • DMP168: Digital audio matrix processor (16 inputs, 8 outputs)

Development

Project Structure

blustream/
├── blustream/              # Main package
│   ├── base/                # Base classes and interfaces
│   ├── connection/          # Connection implementations
│   ├── devices/             # Device-specific implementations
│   │   └── dmp168/          # DMP168 device
│   └── cli/                 # CLI implementation
├── tests/                   # Test suite
├── main.py                  # CLI entry point
└── README.md               # This file

Running Tests

pytest tests/

Lua development

The Control4 driver lives under control4/ and targets Lua 5.1 (the version the Control4 Composer sandbox runs). CI lints all Lua sources with luacheck (see lint-control4.yml) and runs the unit tests with busted (see test-control4.yml).

To install the toolchain locally:

# macOS
brew install lua@5.1 luarocks
luarocks --lua-version=5.1 install luacheck
luarocks --lua-version=5.1 install busted

# Debian / Ubuntu
sudo apt-get install lua5.1 liblua5.1-0-dev luarocks
sudo luarocks --lua-version=5.1 install luacheck
sudo luarocks --lua-version=5.1 install busted

Then, from the repo root:

luacheck .                              # lint all Lua source
busted --pattern=_spec control4/        # run Lua unit tests

Commit hooks (secret scanning + linting)

Commits are gated by pre-commit, which runs betterleaks (a secret scanner — gitleaks' feature-frozen successor) alongside ruff, ruff-format, luacheck and a large-file guard. The secret scanner uses the shared .gitleaks.toml, which adds custom IPv4/IPv6/MAC rules so a real device identifier can't be committed — example identifiers must use the IETF documentation ranges listed in docs/secret-scanning-allowlist.md.

Install once per clone:

# macOS
brew install betterleaks pre-commit

# Debian / Ubuntu (betterleaks: see its release page or `go install`)
pipx install pre-commit
go install github.com/betterleaks/betterleaks@v1.4.1

pre-commit install          # wire the hooks into git

Then commits are scanned automatically. To run everything on demand:

pre-commit run --all-files                       # all hooks, whole tree
betterleaks detect --no-git --config .gitleaks.toml   # just the secret scan

CI enforces the same checks server-side so the gate holds even without the local hook installed: the secret scan runs in secret-scan.yml, and ruff / luacheck / the tests run in the per-component lint-* and test-* workflows. ruff-format and the large-file guard are local-only (CI does not enforce whole-tree formatting, so legacy files aren't reformatted until touched).

License

This project is licensed under the Apache License 2.0.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request. Before your first commit, install the commit hooks (brew install betterleaks pre-commit && pre-commit install) so the secret scan and linters run locally.

Future Enhancements

See FUTURE_ENHANCEMENTS.md for planned features and improvements.

Metadata

Release files for blustream 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for blustream 0.3.0
File Size Uploaded
blustream-0.3.0.tar.gz 81.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for blustream 0.3.0
File Interpreter ABI Platform
blustream-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 128.6 kB

Release files / blustream-0.3.0.tar.gz

Download URL blustream-0.3.0.tar.gz
Size 81.6 kB
Tags Source
SHA-256 checksum
How to use checksums
eb01a6acd1bb6f7a5243e616d4b44040d7f8b83e08949f214d72bb373e9e7f29
BLAKE2b-256 checksum
How to use checksums
7282007588c46eaeca093a22b2c5af0cae0db4b32d5e532540354c1ed9482169
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 17, 2026.

Transparency log

Release files / blustream-0.3.0-py3-none-any.whl

Download URL blustream-0.3.0-py3-none-any.whl
Size 47.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f9b14e895738f15fc185839799ed37b19279b9f87b400e225cef91a623bcd495
BLAKE2b-256 checksum
How to use checksums
8c9217d735aeedeb94604783485b760b8f68160e9527c1abb4977b7962c6d5de
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 17, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page