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.0.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.0-py3-none-any.whl (13.5 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: elecnova_client-0.2.0.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.0.tar.gz
Algorithm Hash digest
SHA256 b12279f0343bef8f697b539ded7114fa0f590c3ddbc791d56a120de14f689cbd
MD5 1815a2ea250b808cc9ba0898ce742a55
BLAKE2b-256 e73b3f41cb8b295f86413671296f49552bf32a4129a119585a2ccd30eadcbcb6

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for elecnova_client-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b26296fc5dc20cf4b874366acd89359e87a23c76c6d40cfe097de0ebc9d674dc
MD5 5b026da6c6a2791e242ebaef4fed7634
BLAKE2b-256 40f35608c13bf3701b6207ae64c4c13e8e3b98e1af4dcc48b99dba0bf7e8d61c

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