Skip to main content

Python client for interfacing with the Trinnov Altitude processor.

Project description

Trinnov Altitude Python Library

CI PyPI Python Version

Async Trinnov Altitude client for long-running integrations (Home Assistant primary target).

Version 2.0

Version 2.x is a clean break from 1.x.

  • No compatibility shims
  • New lifecycle (start / wait_synced / stop)
  • New state model (client.state)
  • Optional command ACK handling

Read the migration guide: docs/MIGRATION_V2.md

Installation

pip install trinnov-altitude

Quick Start

import asyncio

from trinnov_altitude.client import TrinnovAltitudeClient


async def main() -> None:
    client = TrinnovAltitudeClient(host="192.168.1.90")

    try:
        await client.start()
        await client.wait_synced(timeout=10)

        await client.volume_set(-30.0)
        await client.mute_on()

        print(client.state.volume)
        print(client.state.source)
    finally:
        await client.stop()


asyncio.run(main())

Lifecycle

  • await client.start() connects, bootstraps, and starts the read loop.
  • await client.wait_synced() waits until welcome + catalogs + current indices are observed.
  • await client.stop() stops listener and disconnects cleanly.

Protocol Semantics

The client parses raw messages first, then normalizes them into canonical state events. This keeps protocol quirks isolated and keeps the state reducer deterministic.

  • Canonical identity:
    • CURRENT_PRESET <n>
    • CURRENT_PROFILE <n> or index-only PROFILE <n>
    • DECODER ... UPMIXER <mode>
  • Optional catalogs:
    • Presets via LABELS_CLEAR + LABEL <n>: <name>
    • Sources via PROFILES_CLEAR + PROFILE <n>: <name>
  • Quirk profiles:
    • altitude_ci is selected when IDENTS includes altitude_ci
    • In that profile, META_PRESET_LOADED <n> is normalized as a source-change signal

Catalog messages may arrive late, be refreshed, or be absent. Consumers should not assume labels are always present.

Events

def on_event(event, message):
    if event == "connected":
        ...
    elif event == "disconnected":
        ...
    elif event == "received_message":
        ...

client.register_callback(on_event)

Callback exceptions are isolated and logged (they do not crash the listener).

HA Adapter

Use trinnov_altitude.adapter.AltitudeStateAdapter to convert mutable runtime state into immutable snapshots plus typed deltas/events:

  • snapshot: stable full-state view for coordinator data
  • deltas: field-level changes since previous snapshot
  • events: integration-friendly event stream (volume, mute, source, preset, etc.)

You can wire this directly through the client:

from trinnov_altitude.adapter import AltitudeStateAdapter

adapter = AltitudeStateAdapter()

def on_update(snapshot, deltas, events):
    ...

handle = client.register_adapter_callback(adapter, on_update)
# later: client.deregister_adapter_callback(handle)

For Home Assistant coordinator/event-bus integration, use trinnov_altitude.ha_bridge:

  • coordinator_payload(snapshot)
  • to_ha_events(events)
  • build_bridge_update(snapshot, deltas, events)

Command ACKs

You can use fire-and-forget commands (default) or explicit ACK waiting:

await client.volume_set(-20.0)
await client.command("volume -20", wait_for_ack=True, ack_timeout=2.0)

Development

uv sync --group dev
uv run ruff check .
uv run ruff format --check .
uv run ty check trinnov_altitude
uv run pytest -v

Or use task wrappers:

task dev
task check

Real Device Integration Tests (Read-Only)

The test suite includes a manual, read-only integration tier for validating behavior against real hardware.

  • Marker: integration_real
  • Opt-in gate: TRINNOV_ITEST=1
  • Target host: TRINNOV_HOST=<ip-or-hostname>
  • Optional port override: TRINNOV_PORT=44100
  • If the device is offline/unreachable, tests are skipped.

These tests intentionally avoid mutating commands (no power/preset/source/volume state changes).

TRINNOV_ITEST=1 TRINNOV_HOST=192.168.30.3 task test:integration-real

Pyx (optional)

Pyx is optional in this repo. You can keep publishing to PyPI/TestPyPI only.

  • Install via Pyx: authenticate uv with PYX_API_KEY and configure your Pyx index URL in uv (uv add --index ... / uv sync).
  • Publish to Pyx: run the Release workflow manually with target=pyx after setting repository secrets PYX_API_KEY and PYX_PUBLISH_URL.
  • No dual-publish requirement: use Pyx when you need private/internal package distribution or policy control.

Release

  1. Merge conventional-commit changes to master.
  2. Wait for the release-please workflow to open/update a release PR.
  3. Review and merge the release PR (this updates CHANGELOG.md and __version__).
  4. Release Please creates the GitHub Release and tag.
  5. The Release workflow publishes artifacts to PyPI automatically for published releases.
  6. For TestPyPI or Pyx-only publishing, run Release manually with workflow_dispatch.

Maintenance

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

trinnov_altitude-3.2.5.tar.gz (239.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

trinnov_altitude-3.2.5-py3-none-any.whl (26.6 kB view details)

Uploaded Python 3

File details

Details for the file trinnov_altitude-3.2.5.tar.gz.

File metadata

  • Download URL: trinnov_altitude-3.2.5.tar.gz
  • Upload date:
  • Size: 239.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for trinnov_altitude-3.2.5.tar.gz
Algorithm Hash digest
SHA256 b24f6b88d79aa816196560702e7273cfbd45dd035f8e478f80b45c646f9db02c
MD5 d18927d7636f84d6ce104f4417436b08
BLAKE2b-256 a91e01c52aba155a27b86d76430219a64eb8657287787b893d83a3fe46a7d101

See more details on using hashes here.

Provenance

The following attestation bundles were made for trinnov_altitude-3.2.5.tar.gz:

Publisher: publish.yml on binarylogic/py-trinnov-altitude

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file trinnov_altitude-3.2.5-py3-none-any.whl.

File metadata

File hashes

Hashes for trinnov_altitude-3.2.5-py3-none-any.whl
Algorithm Hash digest
SHA256 762b9786d5238caba4a237b33d6c11a136bd5ba3edb1115ace7c940d4cad74b0
MD5 5a21f8b8977e958421d4c23bcb418501
BLAKE2b-256 4e7f19eb3300d65803a025f7cccff88bb71f9e381c9318a34be7f2aa1569a599

See more details on using hashes here.

Provenance

The following attestation bundles were made for trinnov_altitude-3.2.5-py3-none-any.whl:

Publisher: publish.yml on binarylogic/py-trinnov-altitude

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page