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

Uploaded Python 3

File details

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

File metadata

  • Download URL: pysaj_elekeeper-0.0.10.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.10.tar.gz
Algorithm Hash digest
SHA256 d4cc10a7bc21d86a69b87c837b88ec4d83a9f0eb2fe188dbbd22826bc4feb490
MD5 ef84e613b2c4114cd002a5f7abf25ea1
BLAKE2b-256 3ef4b83602f545215205b2d9a644d10a912b22f867d7e97a3413497c3bf8fd8d

See more details on using hashes here.

Provenance

The following attestation bundles were made for pysaj_elekeeper-0.0.10.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.10-py3-none-any.whl.

File metadata

File hashes

Hashes for pysaj_elekeeper-0.0.10-py3-none-any.whl
Algorithm Hash digest
SHA256 f38de48790438c38d56d63f46329d6c366f851878b444c34a7311d4513b42752
MD5 2af927bf10acb8ad9e197a9c8125cdf7
BLAKE2b-256 053890198292be1480ebfbf2236ee0ed461c1e9f29e7ce84dcf1e958f2ce21b8

See more details on using hashes here.

Provenance

The following attestation bundles were made for pysaj_elekeeper-0.0.10-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