Skip to main content

Async Python client for the DIVERA 24/7 REST API.

Project description

divera247

An async Python client for the DIVERA 24/7 REST API and WebSocket push stream, built on httpx and pydantic.

Installation

pip install divera247
# or, with uv:
uv add divera247

Optional: WebSocket streaming

The push-event WebSocket subscription talks to wss://ws.divera247.com/ws via httpx-ws, which is kept out of the default install for users who only need the REST API. Install it through the ws extra:

pip install 'divera247[ws]'
# or, with uv:
uv add 'divera247[ws]'

Quickstart

import anyio
from divera247 import AccessKeyAuth, Divera247Client


async def main() -> None:
    async with Divera247Client(auth=AccessKeyAuth('YOUR_ACCESS_KEY')) as client:
        alarms = await client.alarm.get_alarms()
        for alarm in alarms.data or []:
            print(alarm)


anyio.run(main)

Every v2 endpoint group is exposed as a lazily-instantiated attribute on Divera247Client:

Attribute Endpoint group
client.alarm /api/v2/alarms
client.attachment /api/v2/attachments
client.auth_api /api/v2/auth
client.dashboard /api/v2/dashboard
client.event /api/v2/events
client.file /api/v2/file
client.message /api/v2/messages
client.message_channel /api/v2/message-channels
client.news /api/v2/news
client.operations /api/v2/operations
client.password /api/v2/password
client.pull /api/v2/pull
client.reporttype /api/v2/reporttypes
client.shift_plans /api/v2/shift-plans
client.statusgeber /api/v2/statusgeber
client.using_vehicle /api/v2/using-vehicles
client.using_vehicle_crew /api/v2/using-vehicles/...
client.using_vehicle_property /api/v2/using-vehicles/...

Authentication

Three auth flows are provided in divera247.auth, all of which set the Authorization: Bearer <token> header so the same credentials work for both REST and WebSocket:

from divera247 import AccessKeyAuth, JwtAuth, RefreshingJwtAuth

# Static access key (simplest; no token refresh).
AccessKeyAuth('YOUR_ACCESS_KEY')

# Pre-obtained JWT.
JwtAuth('eyJhbGciOi...')

# Access-key backed JWT that is fetched on first use and refreshed shortly
# before `exp`. Safe to share between concurrent tasks.
RefreshingJwtAuth('YOUR_ACCESS_KEY')

Error handling

HTTP errors and envelope errors (success: false) are both funnelled through the hierarchy in divera247.errors:

from divera247 import (
    DiveraAPIError,
    DiveraAuthError,
    DiveraRateLimitError,
    DiveraValidationError,
)

try:
    await client.alarm.get_alarms()
except DiveraAuthError:
    ...                               # 401 / 403
except DiveraRateLimitError as exc:
    await anyio.sleep(exc.retry_after or 1)
except DiveraValidationError as exc:
    print(exc.errors)                 # field -> message mapping
except DiveraAPIError as exc:
    print(exc.status_code, exc.body)  # catch-all for other HTTP errors

Endpoints that return the standard {"success": ..., "data": ...} envelope can be additionally guarded with ensure_success(parsed) when success=false bodies should turn into exceptions.

Customising the HTTP client

Divera247Client is deliberately a thin wrapper: its own constructor only takes the auth, an optional base_url, and an optional pre-built session. Anything you'd normally configure on an httpx.AsyncClient -- timeouts, headers (including User-Agent), proxies, transports, event hooks -- is done by building your own client and passing it in via session=:

import httpx

async with httpx.AsyncClient(
    auth=AccessKeyAuth('...'),
    base_url='https://app.divera247.com/api/',
    timeout=httpx.Timeout(60.0, connect=15.0),
    headers={'User-Agent': 'my-app/1.0', 'Accept-Language': 'de'},
    proxy='http://proxy.local:3128',
    verify=False,
) as external:
    client = Divera247Client(auth=AccessKeyAuth('...'), session=external)
    ...

When a session= is passed the caller keeps ownership: the session is not closed when the client is exited.

WebSocket streaming

Two entry points live in divera247.websocket:

  • subscribe_websocket(client, ...) yields events from a single session and exits when the server disconnects. Use it when you want to drive your own reconnect policy.
  • stream_websocket(client, ...) wraps subscribe_websocket in a jittered exponential-backoff reconnect loop. Use it when you want a "just keep me subscribed" iterator.
from divera247.websocket import (
    ClusterPullEvent,
    ClusterVehicleEvent,
    UnknownEvent,
    UserStatusEvent,
    stream_websocket,
)

async for event in stream_websocket(client, ucr_id=1_234):
    match event:
        case UserStatusEvent(ucr=ucr, status=status):
            ...                                   # status is a PullStatusData
        case ClusterPullEvent(cluster=cluster, pull=pull):
            ...                                   # re-fetch pull.type (e.g. "alarm") + pull.id
        case ClusterVehicleEvent(cluster=cluster, vehicle=vehicle):
            ...                                   # vehicle.id / vehicle.fmsstatus_id update
        case UnknownEvent():
            ...                                   # forward-compatible fallback

WebSocketAuthenticationError propagates out of the loop so an unusable credential doesn't get retried forever.

API schemas

The schemas/ directory contains the vendor-published OpenAPI YAML files that this client was built against -- see schemas/README.md for details and the mapping to divera247.endpoints / divera247.models.

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

divera247-0.0.1b5.tar.gz (50.5 kB view details)

Uploaded Source

Built Distribution

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

divera247-0.0.1b5-py3-none-any.whl (70.8 kB view details)

Uploaded Python 3

File details

Details for the file divera247-0.0.1b5.tar.gz.

File metadata

  • Download URL: divera247-0.0.1b5.tar.gz
  • Upload date:
  • Size: 50.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for divera247-0.0.1b5.tar.gz
Algorithm Hash digest
SHA256 08fe4d97272d33e6f0cc4c268698b19ce72eaae933eff0b459478d13e4232b93
MD5 0863857bc61fffa6737c09a5916ff8e9
BLAKE2b-256 6d261ee916ffd8d683415462e39830873c39ff0effde4aa5ab38bff55c826526

See more details on using hashes here.

File details

Details for the file divera247-0.0.1b5-py3-none-any.whl.

File metadata

  • Download URL: divera247-0.0.1b5-py3-none-any.whl
  • Upload date:
  • Size: 70.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for divera247-0.0.1b5-py3-none-any.whl
Algorithm Hash digest
SHA256 4131c756687cc3c52f664a25b7bb1bb8ea3a3ef7fb346c13066d68a0b1b16799
MD5 1bdfd10ae194849c9c930301220fdaac
BLAKE2b-256 83ecbcc179e4def98cbb7f816611593c2161a3568c7da5277e5ec184253e8c57

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