Skip to main content

Python client for Elecnova ECO EMS Cloud API

Project description

Elecnova Client

Python client library for the Elecnova ECO EMS Cloud API.

Version 0.1.6 - Complete authentication fix and API v1.3.1 support (WORKING!).

Features

  • 🔐 HMAC-SHA256 authentication with automatic token management
  • 📦 Type-safe Pydantic models for API responses
  • ⚡ Async HTTP client using httpx
  • 🔄 Synchronous wrapper for non-async environments
  • 🌞 Photovoltaic power generation endpoints (v1.3.1+)
  • 🔧 Component type standardization with official codes
  • ✅ Comprehensive test coverage
  • 🚀 Zero dependencies on specific frameworks (works with any Python application)

Installation

# From PyPI (recommended)
pip install elecnova-client

# From GitHub
pip install git+https://github.com/elektriciteit-steen/elecnova-client.git

# From source (for development)
git clone https://github.com/elektriciteit-steen/elecnova-client.git
cd elecnova-client
pip install -e ".[dev]"

# Install pre-commit hooks
pre-commit install

Migration Guide

v0.1.5 → v0.1.6 (AUTHENTICATION FIX - NOW WORKING!)

Version 0.1.6 includes critical authentication fixes that make the client fully functional with the Elecnova API.

What Changed:

  • ✅ Fixed business API authentication (raw token + all signature headers)
  • ✅ Fixed MQTT subscription endpoint (GET instead of POST)
  • ✅ Fixed response parsing for raw API responses
  • ✅ Updated models to match actual API response format

No code changes required - simply upgrade to v0.1.6:

pip install --upgrade elecnova-client

Verified Working:

  • ✅ Authentication (/comm/client)
  • ✅ Get cabinets (/api/v1/dev) - Successfully retrieves all cabinets
  • ✅ Get components (/api/v1/dev/{sn}) - Successfully retrieves all components
  • ✅ All v1.3.1 features (component, component_desc fields)

v0.1.4 → v0.1.5 (ENDPOINT CORRECTIONS)

Version 0.1.5 fixed critical endpoint paths to match official documentation:

Method Old (v0.1.4) New (v0.1.5)
get_cabinets() /api/v1/cabinet/list /api/v1/dev
get_components() /api/v1/cabinet/{sn}/components /api/v1/dev/{sn}

Usage

Async Client

from elecnova_client import ElecnovaClient

async def main():
    client = ElecnovaClient(
        client_id="your_client_id",
        client_secret="your_client_secret"
    )

    # Fetch ESS cabinets (devices)
    cabinets = await client.get_cabinets(page=1, page_size=100)
    for cabinet in cabinets:
        print(f"Cabinet: {cabinet.sn} - {cabinet.name}")
        print(f"  Model: {cabinet.model}")
        print(f"  Timezone: {cabinet.time_zone}")

    # Fetch components for a specific cabinet
    components = await client.get_components(cabinet_sn="ESS123456")
    for component in components:
        print(f"Component: {component.sn}")
        print(f"  Type: {component.type}")
        print(f"  Component Code: {component.component}")  # v1.3.1+
        print(f"  Description: {component.component_desc}")  # v1.3.1+
        print(f"  State: {component.state}")

    # Subscribe to MQTT topics for real-time data
    result = await client.subscribe_mqtt_topics(
        device_id="123",
        sn="ESS123456"
    )

    # Fetch PV power generation with 5-minute intervals (v1.3.1+)
    power_data = await client.get_pv_power_cap(
        sn="PV123456",
        begin="2025-11-01T00:00:00Z",
        end="2025-11-01T23:59:59Z"
    )
    for point in power_data:
        print(f"{point.time}: {point.value}W")

    # Get PV daily generation for past 7 days (v1.3.1+)
    daily_data = await client.get_pv_power_gen_daily(sn="PV123456")
    for point in daily_data:
        print(f"{point.time}: {point.value} kWh")

    # Get PV monthly generation (v1.3.1+)
    monthly_data = await client.get_pv_power_gen_monthly(
        sn="PV123456",
        month="2025-11"
    )

    # Get PV yearly generation (v1.3.1+)
    yearly_data = await client.get_pv_power_gen_yearly(
        sn="PV123456",
        year="2025"
    )

    # Always close the client when done
    await client.close()

Context Manager (Recommended)

async def main():
    async with ElecnovaClient(
        client_id="your_client_id",
        client_secret="your_client_secret"
    ) as client:
        cabinets = await client.get_cabinets()
        # Client automatically closes when exiting context

Sync Client

from elecnova_client import ElecnovaClientSync

client = ElecnovaClientSync(
    client_id="your_client_id",
    client_secret="your_client_secret"
)

# Fetch cabinets (synchronous)
cabinets = client.get_cabinets(page=1, page_size=100)
for cabinet in cabinets:
    print(f"Cabinet: {cabinet.sn} - {cabinet.name}")

API Reference

Models

Cabinet

ESS Cabinet (Device) data model with pagination support.

Fields:

  • id: Unique device ID
  • sn: Serial number
  • name: Cabinet name
  • model: Cabinet model
  • time_zone: Installation timezone
  • created_at: Creation timestamp
  • updated_at: Last update timestamp

Component

Component (BMS, PCS, Meter, Sensors, etc.) data model.

Fields:

  • sn: Component serial number (unique identifier)
  • name: Component name
  • model: Component model
  • type: Component type (legacy field)
  • state: Component state (online/offline)
  • location_code: Location code for data point mapping
  • cabinet_sn: Parent cabinet serial number
  • component: Component type code [v1.3.1+] - see Component Types section
  • component_desc: Component type description [v1.3.1+] - see Component Types section

PowerDataPoint

PV power generation data point [v1.3.1+].

Fields:

  • time: Timestamp in RFC3339 format
  • value: Power value (unit varies by endpoint)

TokenResponse

OAuth token response (internal use).

Fields:

  • id: MQTT Client ID
  • username: MQTT username
  • password: MQTT password
  • token: Bearer token (24-hour TTL)

Component Types (v1.3.1+)

The API now provides standardized component type codes in the component field:

Code Description Usage
ess.ems EMS Energy Management System
ess.bms BMS Battery Management System
ess.pcs PCS Power Conversion System
pv.inv PV Photovoltaic Inverter
ess.meter Meter Energy Meter
ess.battery Battery Battery Pack
ess.fire Fire Host Fire Suppression System
ess.ac Air Conditioning HVAC System

Access these via component.component (code) and component.component_desc (description).

Client Methods

Authentication

  • get_token(): Obtain/refresh access token (automatically called, 24-hour TTL)

Device Management

  • get_cabinets(page=1, page_size=100): List ESS cabinets with pagination
    • Endpoint: GET /api/v1/dev
    • Returns: List of Cabinet objects
  • get_components(cabinet_sn): List components for a specific cabinet
    • Endpoint: GET /api/v1/dev/{sn}
    • Returns: List of Component objects

MQTT Subscription

  • subscribe_mqtt_topics(device_id, sn): Subscribe to MQTT topics for real-time data
    • Endpoint: POST /api/v1/dev/topic/{device_id}/{sn}
    • Returns: Subscription result dictionary

PV Power Generation [v1.3.1+]

  • get_pv_power_cap(sn, begin, end): Get PV power generation with 5-minute intervals
    • Endpoint: GET /api/v1/dev/pv/power-cap/{sn}
    • Params: begin and end in RFC3339 format (e.g., "2025-11-01T00:00:00Z")
    • Returns: List of PowerDataPoint (power in watts)
  • get_pv_power_gen_daily(sn): Get PV daily generation for past 7 days
    • Endpoint: GET /api/v1/dev/pv/power-gen/daily/{sn}
    • Returns: List of PowerDataPoint (daily energy in kWh)
  • get_pv_power_gen_monthly(sn, month): Get PV monthly daily generation
    • Endpoint: GET /api/v1/dev/pv/power-gen/monthly/{sn}
    • Params: month in YYYY-MM format (e.g., "2025-11")
    • Returns: List of PowerDataPoint (daily energy for the month)
  • get_pv_power_gen_yearly(sn, year): Get PV annual monthly generation
    • Endpoint: GET /api/v1/dev/pv/power-gen/yearly/{sn}
    • Params: year in YYYY format (e.g., "2025")
    • Returns: List of PowerDataPoint (monthly energy for the year)

Exception Handling

from elecnova_client import (
    ElecnovaAPIError,
    ElecnovaAuthError,
    ElecnovaRateLimitError,
    ElecnovaTimeoutError,
)

try:
    cabinets = await client.get_cabinets()
except ElecnovaAuthError as e:
    print(f"Authentication failed: {e}")
    print(f"Status code: {e.status_code}")
    print(f"Response: {e.response}")
except ElecnovaRateLimitError as e:
    print(f"Rate limit exceeded: {e}")
except ElecnovaTimeoutError as e:
    print(f"Request timeout: {e}")
except ElecnovaAPIError as e:
    print(f"API error: {e}")

Development

# Install dev dependencies
pip install -e ".[dev]"

# Run tests
pytest

# Run tests with coverage
pytest --cov=elecnova_client --cov-report=html

# Run linter
ruff check .

# Format code
ruff format .

# Type checking
mypy src/

API Documentation

Based on Elecnova ECO EMS Cloud API Interface Document V1.3.1

Authentication Flow

  1. Client Registration: Obtain Client ID and Client Secret from Elecnova
  2. IP Whitelisting: Provide source IP address for access approval
  3. Token Request: Call GET /comm/client with HMAC-SHA256 signature
  4. Token Usage: Include Bearer token in Authorization header for all API calls
  5. Token Refresh: Automatic refresh 5 minutes before 24-hour expiry

Technical Specifications

  • Authentication: HMAC-SHA256 signature with Base64 encoding
  • Token Validity: 24 hours (86400 seconds)
  • Token Refresh: Automatic, 5 minutes before expiry
  • Rate Limit: 100 requests/second
  • MQTT Protocol: MQTTS (secure MQTT)
  • MQTT Port: 1884
  • Base URL: https://api.elecnova.com (configurable)
  • Timeout: 30 seconds (configurable)

API Endpoints (v1.3.1)

Endpoint Method Description
/comm/client GET Request authentication token and MQTT credentials
/api/v1/dev GET Get device list (ESS cabinets) with pagination
/api/v1/dev/{sn} GET Get device component information
/api/v1/dev/topic/{device_id}/{sn} POST Subscribe to MQTT topics
/api/v1/dev/pv/power-cap/{sn} GET Get PV power generation (5-min intervals)
/api/v1/dev/pv/power-gen/daily/{sn} GET Get PV daily generation (past 7 days)
/api/v1/dev/pv/power-gen/monthly/{sn} GET Get PV monthly generation
/api/v1/dev/pv/power-gen/yearly/{sn} GET Get PV yearly generation

Changelog

See CHANGELOG.md for detailed version history.

License

LGPL-3.0-or-later

Support

For issues, feature requests, or contributions, please visit: https://github.com/elektriciteit-steen/elecnova-client

Author

Steen Elektriciteit

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

elecnova_client-0.2.1.tar.gz (14.9 kB view details)

Uploaded Source

Built Distribution

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

elecnova_client-0.2.1-py3-none-any.whl (13.6 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: elecnova_client-0.2.1.tar.gz
  • Upload date:
  • Size: 14.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.14

File hashes

Hashes for elecnova_client-0.2.1.tar.gz
Algorithm Hash digest
SHA256 3043937a519894f063a233ef3883c3bdbb0c69b9de2ef9d59ede2682545b235d
MD5 b5789e3f8e12215df2555a236ae05a72
BLAKE2b-256 43b68904fbc09e96eead085c7c28bf82fae7cab78887febaf419a18c9700340c

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for elecnova_client-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 02e3367ec4e1e24e516b82d2efa6bacdb011fcacf651afc6677495a8bb66e726
MD5 799d91c491d6b3f22e10bcbe4e25291a
BLAKE2b-256 d92157d8e09c08c7acc5b5fb80a12a1f6d4089cadf54c41c413f4700e57732b3

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