Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

Latest Tag PyPI Version Python Versions License CI Status Codecov CodeQL Status OpenSSF Best Practices OpenSSF Baseline Docs Status Documentation Renovate Code Style: Ruff Type Checked: mypy Security: Bandit Release Status Last Commit Repo Size PyPI Downloads

Status: Stable | Python 3.13.2+ required

Python library for integrating with BragerOne-compatible cloud and realtime APIs.

Supported platforms:

  • BragerOne (default): one.brager.pl / io.brager.pl

  • TiSConnect: www.tisconnect.info / io.tisconnect.info

Features: - Async REST client (httpx, not aiohttp) - Realtime updates (python-socketio, namespace /ws) - Event bus for updates - ParamStore (lightweight, key→value with optional rich metadata via LiveAssetsCatalog) - CLI for diagnostics - Home Assistant ready

Installation

Stable (PyPI):

pip install py-bragerone

Pre-release (PyPI, exact pin):

pip install "py-bragerone==2026.8.9rc1"

Optional extras:

pip install "py-bragerone[cli]"      # CLI with typer, rich, aiofiles
pip install "py-bragerone[keyring]"  # Secure token storage with keyring

Development Dependencies

For building documentation with architectural diagrams:

# Ubuntu/Debian
sudo apt-get install graphviz

# macOS
brew install graphviz

# Windows (via Chocolatey)
choco install graphviz

CLI usage

Run the CLI for guided login and WS session (the password is prompted securely when omitted):

pybragerone-cli --email YOU@example.com

Select platform (useful for TiSConnect installations):

pybragerone-cli --platform tisconnect --email YOU@example.com

Examples

Basic login and device listing

Minimal async example showing login and listing objects/modules:

import asyncio
import os
from pybragerone.api import BragerOneApiClient

async def main() -> None:
    email = os.getenv("PYBO_EMAIL", "user@example.com")
    password = os.getenv("PYBO_PASSWORD", "password")
    client = BragerOneApiClient()
    try:
        print(f"Logging in as {email}...")
        await client.ensure_auth(email, password)
        print("✓ Login successful")

        objects = await client.get_objects()
        print(f"Found {len(objects)} heating system(s)")
        for obj in objects:
            print(f"- {obj.name} (id={obj.id})")
            modules = await client.get_modules(obj.id)
            for m in modules:
                devid = m.devid or f"id:{m.id}"
                version = m.moduleVersion or (m.gateway.version if m.gateway else "unknown")
                print(f"  • {m.name} (devid={devid}, version={version})")
    finally:
        await client.close()

if __name__ == "__main__":
    asyncio.run(main())

Real-time parameter monitoring

Subscribing to updates via BragerOneGateway and printing changes:

import asyncio
import os
from contextlib import suppress
from pybragerone import BragerOneGateway

async def main() -> None:
    email = os.getenv("PYBO_EMAIL")
    password = os.getenv("PYBO_PASSWORD")
    object_id = int(os.getenv("PYBO_OBJECT_ID", "0"))
    modules = [m.strip() for m in os.getenv("PYBO_MODULES", "").split(",") if m.strip()]

    if not (email and password and object_id and modules):
        print("Set PYBO_EMAIL, PYBO_PASSWORD, PYBO_OBJECT_ID, PYBO_MODULES")
        return

       gateway = await BragerOneGateway.from_credentials(
             email=email,
             password=password,
             object_id=object_id,
             modules=modules,
       )

    async def monitor() -> None:
        async for ev in gateway.bus.subscribe():
            if ev.value is None:
                continue
            key = f"{ev.pool}.{ev.chan}{ev.idx}"
            print(f"{ev.devid:12} {key:15} = {ev.value}")

      task: asyncio.Task[None] | None = None
      try:
         await gateway.start()
         task = asyncio.create_task(monitor())
         await asyncio.sleep(10)   # demo run
      finally:
         if task is not None:
            task.cancel()
            with suppress(asyncio.CancelledError):
               await task
         await gateway.stop()

if __name__ == "__main__":
    asyncio.run(main())

ParamStore lightweight mode

Attaching ParamStore to the EventBus and reading values:

import asyncio
import os
from contextlib import suppress
from pybragerone import BragerOneGateway
from pybragerone.models.param import ParamStore

async def main() -> None:
    email = os.getenv("PYBO_EMAIL")
    password = os.getenv("PYBO_PASSWORD")
    object_id = int(os.getenv("PYBO_OBJECT_ID", "0"))
    modules = [m.strip() for m in os.getenv("PYBO_MODULES", "").split(",") if m.strip()]

    if not (email and password and object_id and modules):
        print("Set PYBO_EMAIL, PYBO_PASSWORD, PYBO_OBJECT_ID, PYBO_MODULES")
        return

      gateway = await BragerOneGateway.from_credentials(
         email=email,
         password=password,
         object_id=object_id,
         modules=modules,
      )
    store = ParamStore()

    task = asyncio.create_task(store.run_with_bus(gateway.bus))
    try:
        await gateway.start()
        await asyncio.sleep(2)
        params = store.flatten()
        print(f"Total params: {len(params)}")
        for k, v in list(params.items())[:10]:
            print(f"{k:20} = {v}")
    finally:
        task.cancel()
        with suppress(asyncio.CancelledError):
            await task
        await gateway.stop()

if __name__ == "__main__":
    asyncio.run(main())

Documentation

Full documentation: https://marpi82.github.io/py-bragerone

Security

For information about security policies, vulnerability reporting, and known security exceptions, see SECURITY.md.

This project uses property-based testing (Hypothesis) and an optional Atheris fuzz harness under fuzz/ for parser resilience.

Download files

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

Source Distribution

py_bragerone-2026.9.2rc2.tar.gz (142.0 kB view details)

Uploaded Source

Built Distribution

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

py_bragerone-2026.9.2rc2-py3-none-any.whl (154.2 kB view details)

Uploaded Python 3

File details

Details for the file py_bragerone-2026.9.2rc2.tar.gz.

File metadata

  • Download URL: py_bragerone-2026.9.2rc2.tar.gz
  • Upload date:
  • Size: 142.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for py_bragerone-2026.9.2rc2.tar.gz
Algorithm Hash digest
SHA256 95c0817aeac9de87ec6c6b277caf7df61f93da0ba21f351505cfdbb04ea67a61
MD5 a1d89e788c3ff42569ba2941ac8f216d
BLAKE2b-256 5aa39a020021645ed041d79db8cbcbebefa58a0b7b3960f889bf401b0b7be3d4

See more details on using hashes here.

Provenance

The following attestation bundles were made for py_bragerone-2026.9.2rc2.tar.gz:

Publisher: release.yml on marpi82/py-bragerone

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

File details

Details for the file py_bragerone-2026.9.2rc2-py3-none-any.whl.

File metadata

File hashes

Hashes for py_bragerone-2026.9.2rc2-py3-none-any.whl
Algorithm Hash digest
SHA256 890438e4f1ee7067150a30f71bf34cf017ca4bc047543c09f2505fc76cab1e0a
MD5 1168c94016319fe0345a905ec13098f1
BLAKE2b-256 0c4082f0642517f9eba3e58d5954c0270e5b2a12a360922e679ca2612e4547fb

See more details on using hashes here.

Provenance

The following attestation bundles were made for py_bragerone-2026.9.2rc2-py3-none-any.whl:

Publisher: release.yml on marpi82/py-bragerone

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.
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