Skip to main content

Python client for the SAJ Elekeeper API

Project description

pysaj-elekeeper

CI PyPI Python License: MIT Docs

Async Python client for the current SAJ Elekeeper API at https://eop.saj-electric.com/.

Looking for testers! pysaj-elekeeper has been validated against SAJ inverters with serial prefixes R5X (on-grid) and ASS (AC-coupling with battery). If you have a different SAJ device and are willing to test, please open an issue — your feedback helps expand coverage.

pysaj-elekeeper targets the newer Elekeeper web API (/dev-api/api/v1/...) used by the current SAJ portal. It does not use the legacy /saj/login cookie flow.

Status

This package is in alpha. The implemented endpoints have been validated against a real Elekeeper account, but the upstream API is private and can change without notice.

Features

  • Async httpx client.
  • Elekeeper-compatible AES password encryption.
  • Elekeeper-compatible request signing.
  • Login, refresh token, and logout helpers.
  • Plant list and plant detail helpers.
  • Power flow, energy statistics, battery, device, weather, and chart helpers.
  • Raw authenticated GET and POST helpers for endpoints not wrapped yet.
  • CLI discovery sample with JSONL output.
  • CLI plant summary focused on relevant daily values.

Installation

From GitHub:

python -m pip install pysaj-elekeeper

From a local checkout:

git clone https://github.com/giovadroid/pysaj-elekeeper.git
cd pysaj-elekeeper
uv sync --extra dev

Editable install without uv:

python -m venv .venv
. .venv/bin/activate
python -m pip install -e ".[dev]"

Credentials

Create a local .env file from the example:

cp .env.example .env

Then fill:

SAJ_USER=your-email@example.com
SAJ_PASS=your-password
SAJ_BASE_URL=https://eop.saj-electric.com

Library Usage

High-level API for normal integrations:

import asyncio
import os

from elekeeper import SajClient


async def main() -> None:
    async with SajClient() as client:
        await client.authenticate(os.environ["SAJ_USER"], os.environ["SAJ_PASS"])
        overview = await client.get_plant_overview()
        # Or select explicitly:
        # overview = await client.get_plant_overview(plant_name="Home")
        # overview = await client.get_plant_overview(plant_uid="...")

        print(overview.name)
        print(overview.pv_power_w)
        print(overview.battery_soc_percent)


asyncio.run(main())

Lower-level endpoint wrappers are also available when you need raw Elekeeper payloads:

import asyncio
import os

from elekeeper import SajClient


async def main() -> None:
    async with SajClient() as client:
        await client.login(os.environ["SAJ_USER"], os.environ["SAJ_PASS"])

        first = await client.get_primary_plant()
        if first is None:
            return
        plant_uid = first["plantUid"]

        device_sn = await client.get_primary_device_sn(plant_uid)

        flow = await client.get_device_energy_flow(plant_uid, device_sn=device_sn)
        battery = await client.get_one_device_battery_info(device_sn) if device_sn else {}

        print(flow.get("totalPvPower"), battery.get("batEnergyPercent"))


asyncio.run(main())

CLI Examples

Both examples read credentials from a .env file in the current directory:

cp .env.example .env
# edit SAJ_USER and SAJ_PASS

Discovery sample

python examples/sample.py
python examples/sample.py --jsonl elekeeper-sample.jsonl

Logs in, lists plants, fetches the first plant's detail, device, battery, weather, and chart endpoints. Prints a compact discovery summary and writes full endpoint payloads to JSONL.

Plant summary

python examples/plant_summary.py
python examples/plant_summary.py --plant-uid <plant-uid>
python examples/plant_summary.py --plant-name <plant-name>

Prints relevant daily plant values:

  • Current PV, load, grid, and battery power flow.
  • Today's production, load, import, export, battery charge, and battery discharge.
  • Lifetime plant totals.
  • Battery SOC, SOH, voltage, current, temperature, and work time.
  • Device rows with current power, daily production, and SOC where available.

Wrapped Endpoints

Auth and account:

  • authenticate
  • login
  • refresh_access_token
  • logout
  • get_login_info

Plants and home statistics:

  • list_plants
  • get_primary_plant
  • get_plant_by_uid
  • get_plant_by_name
  • get_primary_device_sn
  • get_plant_overview
  • get_end_user_plant_list
  • get_plant_list
  • get_plant_info
  • get_plant_parallel_info
  • get_device_energy_flow
  • get_home_energy_statistics
  • get_home_power_statistics
  • get_home_plant_statistics
  • get_plant_statistics_data
  • get_home_battery_statistics
  • get_home_device_statistics

Devices and battery:

  • get_device_list
  • get_battery_list
  • get_one_device_info
  • get_one_device_battery_info
  • get_order_status_summary_report_info

Weather and charts:

  • get_current_weather
  • get_forecast_weather
  • get_self_use_energy_data
  • get_store_power_analysis_data
  • get_store_energy_compare_data
  • get_store_energy_balance_data
  • get_grid_curve_analysis_data
  • get_grid_energy_statistics_data

Escape hatches:

  • get_raw
  • post_raw

Known Limitations

  • getPlantSankeyDiagram returned upstream errCode=10001 for the tested account and is intentionally not called by the sample.
  • Some endpoints require deviceSn; for the tested plant this came from get_plant_info()["deviceSnList"][0].
  • Some dashboard endpoints use searchOfficeIdArr, available from get_login_info()["officeId"].

API Documentation

Generated from docstrings with pdoc. Hosted at https://giovadroid.github.io/pysaj-elekeeper.

To generate locally:

make docs        # generate HTML → docs/api/
make docs-serve  # live preview at http://localhost:8080

Or directly:

uv run pdoc -o docs/api src/elekeeper

Development

uv sync --extra dev
uv run ruff check .
uv run python -m pytest -q
uv build
uv run twine check dist/*

GitHub Actions:

  • CI validates lint, tests, and package build on pushes and pull requests.
  • Release builds GitHub Release artifacts when pushing a SemVer tag such as v0.1.0.
  • Publish to PyPI is manual and uses PyPI Trusted Publishing. It is included for later use, but GitHub releases are the default publishing path for now.

License

MIT

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

pysaj_elekeeper-0.0.9.tar.gz (18.0 kB view details)

Uploaded Source

Built Distribution

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

pysaj_elekeeper-0.0.9-py3-none-any.whl (14.9 kB view details)

Uploaded Python 3

File details

Details for the file pysaj_elekeeper-0.0.9.tar.gz.

File metadata

  • Download URL: pysaj_elekeeper-0.0.9.tar.gz
  • Upload date:
  • Size: 18.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for pysaj_elekeeper-0.0.9.tar.gz
Algorithm Hash digest
SHA256 727cd617785bd846bb5c439de4edef2260e40f64ee4d0351c3909ae380c7c0ac
MD5 f180bdb39ffd24de667bf26635fa30ee
BLAKE2b-256 d078837b163c91b0da792d50ce6b60a4781dedbfde3a35aace49b746c9f709f4

See more details on using hashes here.

Provenance

The following attestation bundles were made for pysaj_elekeeper-0.0.9.tar.gz:

Publisher: pypi.yml on giovadroid/pysaj-elekeeper

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

File details

Details for the file pysaj_elekeeper-0.0.9-py3-none-any.whl.

File metadata

  • Download URL: pysaj_elekeeper-0.0.9-py3-none-any.whl
  • Upload date:
  • Size: 14.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for pysaj_elekeeper-0.0.9-py3-none-any.whl
Algorithm Hash digest
SHA256 fc395bbe5872cd8b8e11ad2358cf861ab9530693680492dcaaabdb5eaa380568
MD5 d8ddc2320faabd4c9b1bf9c74bcc87c0
BLAKE2b-256 8840eb3d6087bc37b6c0f134208b5ae7a3151264c6c1120f6f70bfc484cc27cb

See more details on using hashes here.

Provenance

The following attestation bundles were made for pysaj_elekeeper-0.0.9-py3-none-any.whl:

Publisher: pypi.yml on giovadroid/pysaj-elekeeper

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