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 periodamount_with_discount— EUR costfields.time_of_read_dt— UTC datetime of the readingfields.meter_value_kwh— cumulative meter reading (kWh)
DailyReading (from UsageReport.readings)
date— UTC datetime of the bucket startkwh— kWh consumedeur— 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.jsonby default (mode0600). Use a customTokenStoreto 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 onawait 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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pyyunoheat-0.2.2.tar.gz.
File metadata
- Download URL: pyyunoheat-0.2.2.tar.gz
- Upload date:
- Size: 45.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0db487e9e6c7ebaea60ef315362677f2e1d1bff5279ac45bb511a1ad99ca43cd
|
|
| MD5 |
1a4b7b0b6f7008ed4974f7a121b370c8
|
|
| BLAKE2b-256 |
a7de299daca4f544c609aee7759760802ed462db80ae3a3e96cc70692db2d4c9
|
Provenance
The following attestation bundles were made for pyyunoheat-0.2.2.tar.gz:
Publisher:
release.yml on Irishsmurf/pyyunoheat
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pyyunoheat-0.2.2.tar.gz -
Subject digest:
0db487e9e6c7ebaea60ef315362677f2e1d1bff5279ac45bb511a1ad99ca43cd - Sigstore transparency entry: 1790511906
- Sigstore integration time:
-
Permalink:
Irishsmurf/pyyunoheat@82cd24821af8654e370e7d0e6117c955d5e74d6d -
Branch / Tag:
refs/tags/v0.2.2 - Owner: https://github.com/Irishsmurf
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@82cd24821af8654e370e7d0e6117c955d5e74d6d -
Trigger Event:
push
-
Statement type:
File details
Details for the file pyyunoheat-0.2.2-py3-none-any.whl.
File metadata
- Download URL: pyyunoheat-0.2.2-py3-none-any.whl
- Upload date:
- Size: 20.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0ec06731e06a831f6bd14f8195d751f5dd7fef9fdfdf819bc8699d66ce77d632
|
|
| MD5 |
6fdc31b2e586624f7bb8b6b50e9b15f6
|
|
| BLAKE2b-256 |
bc953ad0cdccca49f4a81fdc133ddbff15559dd9cec1cd2a97b5438c8fa78dc3
|
Provenance
The following attestation bundles were made for pyyunoheat-0.2.2-py3-none-any.whl:
Publisher:
release.yml on Irishsmurf/pyyunoheat
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pyyunoheat-0.2.2-py3-none-any.whl -
Subject digest:
0ec06731e06a831f6bd14f8195d751f5dd7fef9fdfdf819bc8699d66ce77d632 - Sigstore transparency entry: 1790511970
- Sigstore integration time:
-
Permalink:
Irishsmurf/pyyunoheat@82cd24821af8654e370e7d0e6117c955d5e74d6d -
Branch / Tag:
refs/tags/v0.2.2 - Owner: https://github.com/Irishsmurf
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@82cd24821af8654e370e7d0e6117c955d5e74d6d -
Trigger Event:
push
-
Statement type: