Skip to main content

Lightweight Flowerhub portal client (synchronous and async)

Project description

Flowerhub Portal Python Client

CI Code Coverage Python 3.10+ License

A lightweight, Python client for the Flowerhub portal API with cookie-based JWT authentication.

Related Projects:

Features

  • Cookie-based JWT authentication with automatic token refresh
  • Async/await support via aiohttp
  • Client provides asset, consumption, and invoice data from API endpoints
  • Designed for Home Assistant integrations and similar use cases

Installation

From Source

git clone https://github.com/MichaelPihlblad/flowerhub-portal-api_python-lib.git
cd flowerhub-portal-api_python-lib
pip install -e ".[async]"

Quick Start

import asyncio
from flowerhub_portal_api_client import AsyncFlowerhubClient

async def main():
    async with aiohttp.ClientSession() as session:
        client = AsyncFlowerhubClient(session=session)

        # Login
        result = await client.async_login("user@example.com", "password")

        # Fetch asset information
        await client.async_readout_sequence()

        # Access asset status
        if client.flowerhub_status:
            print(f"Status: {client.flowerhub_status.status}")
            print(f"Message: {client.flowerhub_status.message}")

asyncio.run(main())

Authentication Error Handling

The client automatically handles token refresh on 401 Unauthorized responses. If the refresh fails and the request still returns 401, an AuthenticationError is raised, indicating that the user needs to login again.

Exception-Based Handling

from flowerhub_portal_api_client import AsyncFlowerhubClient, AuthenticationError

try:
    await client.async_fetch_asset_id()
except AuthenticationError:
    # Token refresh failed, re-authentication required
    await client.async_login(username, password)
    await client.async_fetch_asset_id()

Callback-Based Handling

For Home Assistant integrations or event-driven architectures:

def on_auth_failed():
    """Called when authentication fails and re-login is needed."""
    print("Re-authentication required")
    # Trigger reauth flow, set flag, etc.

client = AsyncFlowerhubClient(
    session=session,
    on_auth_failed=on_auth_failed
)

See examples/auth_error_handling.py for complete examples including Home Assistant patterns.

Development Setup

For contributors and local development:

# Clone and setup environment
git clone https://github.com/MichaelPihlblad/flowerhub-portal-api_python-lib.git
cd flowerhub-portal-api_python-lib
python -m venv .venv
source .venv/bin/activate

# Install dependencies
pip install -r requirements.txt
pip install -r dev-requirements.txt

# Install pre-commit hooks
pre-commit install

# Run all checks
pre-commit run --all-files
pytest tests --cov=flowerhub_portal_api_client

Running Examples

Set credentials via environment variables:

export FH_USER="you@example.com"
export FH_PASSWORD="your_password"
python examples/run_example.py

Or create examples/secrets.json:

{
  "username": "you@example.com",
  "password": "your_password"
}

API Documentation

For detailed information about the Flowerhub portal API endpoints used by this Python client library, such as request/response formats, and data structures, see API_DOCUMENTATION.md.

Periodic status refresh (background polling) 💡

The client provides a convenience helper to periodically refresh the asset's flowerHubStatus in a background asyncio Task and deliver updates to your code:

  • start_periodic_asset_fetch(interval_seconds=60, run_immediately=False, on_update=None, result_queue=None)
    • on_update (callable) will be invoked with a FlowerHubStatus object on every successful refresh (called in the event loop).
    • result_queue (an asyncio.Queue) will receive FlowerHubStatus objects via non-blocking put_nowait.
    • interval_seconds must be >= 5 (default 60).

Example (simple async usage):

import asyncio
import aiohttp
from flowerhub_portal_api_client import AsyncFlowerhubClient

async def main():
	async with aiohttp.ClientSession() as session:
		client = AsyncFlowerhubClient(base_url="https://api.portal.flowerhub.se", session=session)
		await client.async_login("user@example.com", "password")

		q = asyncio.Queue()
		client.start_periodic_asset_fetch(60, run_immediately=True, result_queue=q)
		try:
			while True:
				fhs = await q.get()
				print("Queued update:", fhs.status, fhs.message, f"age={fhs.age_seconds():.1f}s")
		finally:
			client.stop_periodic_asset_fetch()

asyncio.run(main())

If you prefer a callback approach, pass on_update which will be called with a FlowerHubStatus instance each time the status is refreshed. Avoid blocking operations in the callback because it's executed in the event loop.

`FlowerHubStatus` fields:
- `status` — textual status (e.g., "Connected")
- `message` — human-friendly message
- `updated_at` — UTC datetime when the status was recorded
- `age_seconds()` — helper returning the age in seconds (float) or `None` if timestamp missing

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

flowerhub_portal_api_client-0.3.0.tar.gz (18.4 kB view details)

Uploaded Source

Built Distribution

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

flowerhub_portal_api_client-0.3.0-py3-none-any.whl (14.2 kB view details)

Uploaded Python 3

File details

Details for the file flowerhub_portal_api_client-0.3.0.tar.gz.

File metadata

File hashes

Hashes for flowerhub_portal_api_client-0.3.0.tar.gz
Algorithm Hash digest
SHA256 7f77d9df898ea38a62b8a64a26050c6cfeffc7a5d5b1830a46f3de61912c7040
MD5 8b9bc0c714d7bfd4a7cfc5879b24c849
BLAKE2b-256 94a07e67d611ebdcd87e542f29da01071936bceaec5179e5b10c9b255c90c847

See more details on using hashes here.

File details

Details for the file flowerhub_portal_api_client-0.3.0-py3-none-any.whl.

File metadata

File hashes

Hashes for flowerhub_portal_api_client-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 63d8dd3c3dafdccd14f9bfcffb4a6aa7e1e61250543318f8409433516b20e5ef
MD5 17e13b9cbc56eb4d7903c4e89e798c4b
BLAKE2b-256 6cdae4616f747f945e338fc0dd31756d3d8617b9a46b67c71f0c56fb8babb51b

See more details on using hashes here.

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