python-evnex
Python client for the Evnex API.
Author not affiliated with Evnex.
Features
- Talks to your Evnex charger via Cloud API
- Automatic retries with exponential backoff
- Automatic re-authentication
- Optionally pass in a
httpxclient - Optionally pass in tokens to resume an existing session
Installation
pip install evnex
Requirements: Python 3.11+
Usage
import asyncio
from pydantic import SecretStr
from pydantic_settings import BaseSettings
from evnex.api import Evnex
class EvnexAuthDetails(BaseSettings):
EVNEX_CLIENT_USERNAME: str
EVNEX_CLIENT_PASSWORD: SecretStr
async def main():
creds = EvnexAuthDetails()
evnex = Evnex(username=creds.EVNEX_CLIENT_USERNAME,
password=creds.EVNEX_CLIENT_PASSWORD.get_secret_value())
user_data = await evnex.get_user_detail()
for org in user_data.organisations:
print("Getting 7 day insight for", org.name, "User:", user_data.name)
insights = await evnex.get_org_insight(days=7, org_id=org.id)
for segment in insights:
print(segment)
if __name__ == '__main__':
asyncio.run(main())
Multifactor authentication
Accounts with MFA enabled can't authenticate with username and password alone: the first API call raises a challenge exception. Catch it, obtain a code from the user, then respond to the challenge:
from pycognito.exceptions import (
SMSMFAChallengeException,
SoftwareTokenMFAChallengeException,
)
evnex = Evnex(username=username, password=password)
try:
evnex.authenticate()
except SoftwareTokenMFAChallengeException:
code = input("Enter the 6-digit code from your authenticator application: ")
evnex.respond_to_mfa_challenge(code, "TOTP")
except SMSMFAChallengeException:
code = input("Enter the 6-digit code you received by SMS: ")
evnex.respond_to_mfa_challenge(code, "SMS")
Note the Cognito challenge session is short-lived (around 3 minutes), so prompt for the code promptly.
The pending challenge is stored on the Evnex instance, so the example above
works because the same instance calls authenticate() and
respond_to_mfa_challenge(). If the response happens somewhere else — a
different process, or a web backend handling a later request — capture the
challenge session from the exception and hand it to the new instance:
try:
evnex.authenticate()
except SoftwareTokenMFAChallengeException as challenge:
challenge_session = challenge.get_tokens() # JSON-serializable dict
# later, on a fresh Evnex instance
evnex.respond_to_mfa_challenge(code, "TOTP", mfa_tokens=challenge_session)
Resuming a session
To avoid interactive MFA on every start, store the tokens after a successful authentication and pass them back in later — the refresh token alone is enough. When the API rejects an expired or revoked access token, the client refreshes it and retries the request automatically:
evnex = Evnex(username=username, password=password, refresh_token=refresh_token)
user_data = await evnex.get_user_detail() # no MFA prompt needed
See examples/get_token.py for a complete MFA + token resumption flow.
Examples
python-evnex is intended as a library, but a few example scripts are provided in the examples folder.
Providing authentication for the examples is via environment variables, e.g. on nix systems:
export EVNEX_CLIENT_USERNAME=you@example.com
export EVNEX_CLIENT_PASSWORD=<your password>
python -m examples.get_charge_point_detail
Developer Notes
Development Setup
# Install dependencies with development tools
uv sync --group dev
# Set up pre-commit hooks (recommended)
uv run pre-commit install
# Alternatively, format and lint manually
uv run ruff format .
uv run ruff check .
Making a new release
What ends up on PyPi is what really matters. Creating a release in GitHub triggers a release workflow that builds and publishes to PyPi.
To manually release, update the version in pyproject.toml, build and publish with uv:
uv build
uv publish
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file evnex-0.6.1.tar.gz.
File metadata
- Download URL: evnex-0.6.1.tar.gz
- Upload date:
- Size: 87.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a2d9aa0df9026c9b75eb44d94bb2fef7ff157df325cb2c19ed460fc04681259d
|
|
| MD5 |
7e04e3090ebf42d6dc6e4b552b65a925
|
|
| BLAKE2b-256 |
d5c401875121cdb70cf08aa5d445285476688f087e396f4eedc201bb209b27da
|
Provenance
The following attestation bundles were made for evnex-0.6.1.tar.gz:
Publisher:
ci.yml on hardbyte/python-evnex
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
evnex-0.6.1.tar.gz -
Subject digest:
a2d9aa0df9026c9b75eb44d94bb2fef7ff157df325cb2c19ed460fc04681259d - Sigstore transparency entry: 2187564667
- Sigstore integration time:
-
Permalink:
hardbyte/python-evnex@9b4a02ea27e7000be397bc9b932df96a048ab010 -
Branch / Tag:
refs/tags/v0.6.1 - Owner: https://github.com/hardbyte
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@9b4a02ea27e7000be397bc9b932df96a048ab010 -
Trigger Event:
release
-
Statement type:
File details
Details for the file evnex-0.6.1-py3-none-any.whl.
File metadata
- Download URL: evnex-0.6.1-py3-none-any.whl
- Upload date:
- Size: 20.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d76d8c0255fa023496c53779159ee139ba658b59a66a714623c8e5c6f3863ea9
|
|
| MD5 |
64124e87df0d8495e9b08d6a7daf22d0
|
|
| BLAKE2b-256 |
c1b1eafaae081ccca24e6ce459fb7baca8b62cbe1c2f636c9493f5307b1c2b25
|
Provenance
The following attestation bundles were made for evnex-0.6.1-py3-none-any.whl:
Publisher:
ci.yml on hardbyte/python-evnex
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
evnex-0.6.1-py3-none-any.whl -
Subject digest:
d76d8c0255fa023496c53779159ee139ba658b59a66a714623c8e5c6f3863ea9 - Sigstore transparency entry: 2187564791
- Sigstore integration time:
-
Permalink:
hardbyte/python-evnex@9b4a02ea27e7000be397bc9b932df96a048ab010 -
Branch / Tag:
refs/tags/v0.6.1 - Owner: https://github.com/hardbyte
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@9b4a02ea27e7000be397bc9b932df96a048ab010 -
Trigger Event:
release
-
Statement type: