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/:
- Python library + CLI (
blustream/). A clean async Python API and ablustreamconsole script. Ships to PyPI onv*tags. - Control4 driver (
control4/dmp168/). A Lua driver packaged as a.c4zarchive that exposes the matrix as a standard Control4 audio matrix. Ships as a GitHub release with the.c4zattached onc4-v*tags. - Home Assistant integration (
custom_components/blustream/). A HACS integration (domainblustream) built to the HA Integration Quality Scale Gold tier. Ships as a GitHub release onhacs-v*tags, which HACS installs from the repository tree. It depends on the publishedblustreamPyPI 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):
- In HACS, open the overflow menu → Custom repositories.
- Add
https://github.com/caidurbin/blustreamwith category Integration. - Install Blustream Audio Matrix, then restart Home Assistant.
- 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)
| File | Size | Uploaded | |
|---|---|---|---|
| blustream-0.3.0.tar.gz | 81.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| 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 logRelease 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