Skip to main content

Async Python client for the Yuno Energy Heat API (Tridens Monetization)

Project description

pyyunoheat

Async Python client for the Yuno Energy Heat API (formerly Kaizen Energy), a communal heating scheme operating across apartment developments in Ireland.

The API runs on the Tridens Monetization platform. This library handles authentication, entity discovery, and data access with no browser or scraping required.

Installation

pip install pyyunoheat

Quick start

Check your current balance

import asyncio
from yunoheat import YunoHeatClient

async def main():
    async with await YunoHeatClient.login("you@example.com", "password") as client:
        balance = await client.get_open_bill_due()
        print(f"Outstanding balance: €{balance.open_bill_due:.2f}")

asyncio.run(main())
Outstanding balance: €87.83

View this week's meter readings

from datetime import datetime, timedelta, UTC
from yunoheat import YunoHeatClient

async def main():
    async with await YunoHeatClient.login("you@example.com", "password") as client:
        now = datetime.now(UTC)
        events = await client.get_usage_events(
            date_from=now - timedelta(days=7),
            date_to=now,
        )
        for e in events.objects:
            print(
                f"{e.fields.time_of_read_dt:%Y-%m-%d}  "
                f"{e.quantity:5.1f} kWh  "
                f"€{e.amount_with_discount:.3f}"
            )

asyncio.run(main())
2026-03-14   5.0 kWh  €1.306
2026-03-13   4.0 kWh  €1.182
2026-03-12   6.0 kWh  €1.430

Daily usage report for the current month

from datetime import datetime, UTC
from yunoheat import YunoHeatClient

async def main():
    today = datetime.now(UTC)
    month_start = today.replace(day=1, hour=0, minute=0, second=0, microsecond=0)

    async with await YunoHeatClient.login("you@example.com", "password") as client:
        report = await client.get_usage_report(date_from=month_start, date_to=today)

    total_kwh = sum(r.kwh for r in report.readings)
    total_eur = sum(r.eur for r in report.readings)

    print(f"{'Date':<12} {'kWh':>6}  {'Cost':>7}")
    print("-" * 28)
    for r in report.readings:
        if r.kwh > 0:
            print(f"{r.date:%Y-%m-%d}  {r.kwh:6.1f}{r.eur:6.3f}")
    print("-" * 28)
    print(f"{'Total':<12} {total_kwh:6.1f}{total_eur:6.3f}")

asyncio.run(main())
Date          kWh     Cost
----------------------------
2026-03-01    3.0  € 0.372
2026-03-02    4.0  € 1.182
2026-03-03    5.0  € 1.306
...
2026-03-14    5.0  € 1.306
----------------------------
Total        58.0  €15.834

Re-use saved tokens (skip re-login)

After the first login() call, tokens are saved to ~/.config/yunoheat/tokens.json. On subsequent runs you can load them directly:

from yunoheat import YunoHeatClient, TokenExpiredError

async def main():
    try:
        # Loads saved tokens; pass credentials for silent re-login on expiry
        client = await YunoHeatClient.from_saved_tokens(
            username="you@example.com",
            password="password",
        )
    except TokenExpiredError:
        # Tokens missing or too old — fall back to full login
        client = await YunoHeatClient.login("you@example.com", "password")

    async with client:
        balance = await client.get_open_bill_due()
        print(f"€{balance.open_bill_due:.2f}")

asyncio.run(main())

API reference

YunoHeatClient

Factory Returns Description
login(username, password, *, token_store=None, session=None) YunoHeatClient Authenticate and create client
from_saved_tokens(username, password, *, token_store=None, session=None) YunoHeatClient Load saved tokens and create client
Method Returns Description
get_open_bill_due() OpenBillDue Current outstanding balance (EUR)
get_usage_events(date_from, date_to, ...) UsageEventsResponse Paginated meter readings
get_usage_report(date_from, date_to, interval) UsageReport Aggregated kWh + EUR by day/week/month
get_person_customer() PersonCustomer Account and contact details
get_invoices(date_from, date_to, ...) InvoicesResponse Paginated invoices
get_bill(bill_id) Bill Single bill by ID
get_credit_balances() CreditBalancesResponse Credit balance on account

get_usage_report accepts interval values: "day" (default), "week", "month", "quarter", "year".

Key model fields

UsageEvent

  • quantity — kWh consumed in this period
  • amount_with_discount — EUR cost
  • fields.time_of_read_dt — UTC datetime of the reading
  • fields.meter_value_kwh — cumulative meter reading (kWh)

DailyReading (from UsageReport.readings)

  • date — UTC datetime of the bucket start
  • kwh — kWh consumed
  • eur — EUR cost

Advanced usage

Custom token storage

By default, tokens are persisted to ~/.config/yunoheat/tokens.json. For Home Assistant or other custom scenarios, you can provide your own TokenStore:

from yunoheat import YunoHeatClient, TokenStore, TokenData
import json

class CustomTokenStore(TokenStore):
    """Example: store tokens in a dict or database."""
    
    async def load(self) -> TokenData | None:
        """Load stored tokens, or None if missing."""
        # e.g., read from database, config store, etc.
        return None
    
    async def save(self, tokens: TokenData) -> None:
        """Persist tokens."""
        # e.g., write to database, config store, etc.
        pass

# Use custom store
store = CustomTokenStore()
client = await YunoHeatClient.login(
    "you@example.com", 
    "password",
    token_store=store,
)

External aiohttp session

For Home Assistant integrations, you can provide an external aiohttp.ClientSession to share it across the application:

import aiohttp
from yunoheat import YunoHeatClient

async with aiohttp.ClientSession() as session:
    client = await YunoHeatClient.login(
        "you@example.com",
        "password",
        session=session,
    )
    # The client uses your session; it won't be closed when client closes
    balance = await client.get_open_bill_due()
    # Session remains open for other tasks

Exception handling

The library raises specific exception types for different error scenarios:

from yunoheat import (
    YunoHeatClient,
    ConfigEntryAuthFailed,  # Invalid credentials; user must re-authenticate
    AuthError,              # Token refresh failed; may be transient
    TokenExpiredError,      # Refresh token expired; requires full login
    APIConnectionError,     # Network error; may be transient
    APIError,               # API returned 4xx/5xx error
    EntityDiscoveryError,   # Bootstrap failed (entity context resolution)
)

async def safe_login(username: str, password: str):
    try:
        return await YunoHeatClient.login(username, password)
    except ConfigEntryAuthFailed:
        print("Invalid credentials. Please check your username and password.")
        raise
    except AuthError as e:
        print(f"Auth error (may be transient): {e}")
        raise
    except APIConnectionError as e:
        print(f"Network error: {e}")
        raise

Notes

  • Token storage: Tokens are persisted to ~/.config/yunoheat/tokens.json by default (mode 0600). Use a custom TokenStore to store tokens elsewhere (e.g., Home Assistant config entry storage).
  • Token refresh: Access tokens expire after 30 minutes. The library refreshes them automatically on demand.
  • Session ownership: If you provide an external aiohttp.ClientSession, the library will not close it. If the library creates its own session, it will be closed on await client.close().
  • Timestamps: All times are UTC. Monetary values are EUR. Energy values are kWh.
  • API endpoint: The underlying API is the Tridens Monetization self-care platform at app.tridenstechnology.com.

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

pyyunoheat-0.2.1.tar.gz (45.6 kB view details)

Uploaded Source

Built Distribution

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

pyyunoheat-0.2.1-py3-none-any.whl (20.0 kB view details)

Uploaded Python 3

File details

Details for the file pyyunoheat-0.2.1.tar.gz.

File metadata

  • Download URL: pyyunoheat-0.2.1.tar.gz
  • Upload date:
  • Size: 45.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for pyyunoheat-0.2.1.tar.gz
Algorithm Hash digest
SHA256 8aaeea61f67639388dcec6d5d0cd2d86aad9f7e2d2943c2d4d4317aee260596a
MD5 d6f810e6a4259e7f0755ba78b26881d4
BLAKE2b-256 f7b5585af241884860faa1ff2914e13d87a584bcbff2da1c127246317d8d45ed

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyyunoheat-0.2.1.tar.gz:

Publisher: release.yml on Irishsmurf/pyyunoheat

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

File details

Details for the file pyyunoheat-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: pyyunoheat-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 20.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for pyyunoheat-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 f3d50f9269a4644e8c5df9e59b0a903c42e71f25f3f6164e0558cbe45cc3523a
MD5 6678294f1286a042858295445639dbef
BLAKE2b-256 1a0c931ba152cf1a04a50167cb53f150607c6d518f00ecddf799b193d2de220b

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyyunoheat-0.2.1-py3-none-any.whl:

Publisher: release.yml on Irishsmurf/pyyunoheat

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