Skip to main content
Yanked

This release has been yanked by its maintainers, and will be ignored by installers, except when explicitly specified.
Consider using release 1.2.2 instead.
Reason given by maintainers: No executionStatus and miscounts rejected events. Use the latest version.

aforo-mqtt-metering

Meter MQTT client traffic — PUBLISH, SUBSCRIBE, UNSUBSCRIBE, CONNECT, DISCONNECT — by wrapping a paho-mqtt (sync) or aiomqtt (async) client. Use it when you connect to a third-party broker (AWS IoT, HiveMQ Cloud, EMQ X Cloud) and want to meter what your client sends and receives.

Version: 1.0.0 · Apache-2.0 · Changelog · User guide

For broker-side (server-level) metering, use the companion EMQ X Erlang plugin in aforo-nextgen-docker/emqx-plugin-aforo-metering/. This Python SDK is client-side.

Install

Intended public install:

pip install aforo-mqtt-metering              # core
pip install "aforo-mqtt-metering[paho]"      # paho-mqtt (sync)
pip install "aforo-mqtt-metering[aiomqtt]"   # aiomqtt (async)
pip install "aforo-mqtt-metering[httpx]"     # faster HTTP flush than stdlib urllib

Not yet on PyPI — install from source for now:

git clone https://github.com/aforoai/SDKs.git
cd SDKs/aforo-metering-sdks/python-mqtt     # folder holding setup.py
pip install -e .
pip install -e ".[paho]"               # or [aiomqtt] / [httpx]

The core package has no required dependencies — the MQTT client libraries and HTTP client are optional extras.

Quickstart — paho-mqtt (sync)

Best when you publish/subscribe from a device or service against a managed broker and want per-event billing without rewriting your MQTT code.

import os
import paho.mqtt.client as mqtt
from aforo_mqtt_metering import AforoMqttBilling, wrap_paho_client

billing = AforoMqttBilling(
    tenant_id="tenant_acme",
    product_id="prod_mqtt_iot_telemetry",
    api_key=os.environ["AFORO_API_KEY"],
    ingestor_url="https://api.aforo.ai",
)

client = mqtt.Client(client_id="device-001")
wrap_paho_client(billing, client, customer_id="cust_acme_001")

client.tls_set()
client.connect("broker.example.com", 8883)
client.subscribe("sensors/+/temperature")
client.publish("devices/001/status", '{"online": true}')
client.loop_forever()

Quickstart — aiomqtt (async)

import aiomqtt
from aforo_mqtt_metering import AforoMqttBilling, wrap_aiomqtt_client

billing = AforoMqttBilling(
    tenant_id="tenant_acme",
    product_id="prod_mqtt_iot_telemetry",
    api_key=os.environ["AFORO_API_KEY"],
    ingestor_url="https://api.aforo.ai",
)

async def main():
    async with aiomqtt.Client("broker.example.com", port=8883, tls_context=ssl_ctx) as c:
        wrap_aiomqtt_client(billing, c, customer_id="cust_acme_001", client_id="device-001")
        await c.subscribe("sensors/+/temperature")
        await c.publish("devices/001/status", '{"online": true}')
        async for msg in c.messages:
            print(msg.topic, msg.payload)

Each metered event POSTs to https://api.aforo.ai/v1/ingest/batch with X-API-Key: <api_key> and X-Tenant-Id: <tenant_id>, carrying mqttEventType, mqttTopic, mqttQos, mqttRetained, mqttClientId, and dataBytes.

⚠ Events are sent to the ingestor's /v1/ingest/batch path as {"events": [...]}, at most 1000 events per request (larger buffers are split). Set ingestor_url to the host only — the SDK appends the path.

customer_id is passed in when you wrap the client — supply it from your trusted device/account mapping, not from anything the broker peer controls. tenant_id is fixed from config and sent as a header.

Configuration

Constructor arguments for AforoMqttBilling(...):

Option Type Default What it does
tenant_id str — (required) Aforo tenant; sent as X-Tenant-Id.
product_id str — (required) Product the events bill against.
api_key str — (required) Aforo API key, sent to the ingestor as X-API-Key.
ingestor_url str — (required) Host; /v1/ingest/batch is appended.
flush_interval_sec float 2.0 Background flush cadence — tightest of the SDKs, since MQTT is high-volume.
flush_count int 200 Buffer size that triggers an immediate flush.
emit_deliver_events bool False Emit a DELIVER event for each inbound on_message (off by default).
on_error Callable[[Exception], None]? logs Called on permanent batch failure, and with the ingestor's errors[].message when it rejects events.
product_type str "MQTT_BROKER" Top-level productType sent on every event (trimmed and upper-cased; values the SDK does not know are passed through). Override per event with push(..., product_type=...) or product_type= on wrap_paho_client / wrap_aiomqtt_client.

Event metric names follow mqtt_broker.<event_type lowercased> (e.g. mqtt_broker.publish, mqtt_broker.subscribe). Retry is fixed at 3 attempts (1s / 2s backoff between them); 408 and 5xx are retried, 429 waits for Retry-After (capped at 60 s), and any other 4xx is not retried.

Walk me through it

Install → wrap the client → publish/subscribe → confirm the event in Aforo, step by step, is in USER_GUIDE.md.

What this doesn't cover

Inbound message delivery is not billed unless you set emit_deliver_events=True — it's off by default to keep volume down. This is client-side metering only; for broker-wide accounting (every client on the broker) use the EMQ X plugin. It doesn't enforce QoS limits or topic ACLs. Pricing, and QoS/retained tiering via filter conditions, are configured in the Aforo console.

Metadata

Release files for aforo-mqtt-metering 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for aforo-mqtt-metering 1.0.0
File Size Uploaded
aforo_mqtt_metering-1.0.0.tar.gz 18.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for aforo-mqtt-metering 1.0.0
File Interpreter ABI Platform
aforo_mqtt_metering-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 27.7 kB

Release files / aforo_mqtt_metering-1.0.0.tar.gz

Download URL aforo_mqtt_metering-1.0.0.tar.gz
Size 18.1 kB
Tags Source
SHA-256 checksum
How to use checksums
9148a85e9ff803dc59b8791fe4fcb91c3bae6ba2a8d6e8a396a09f2a7c690697
BLAKE2b-256 checksum
How to use checksums
e366031b43683257e72c446a687d863af4bacfe8c7553f5d237d0570682d2c34
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 1, 2026.

Transparency log

Release files / aforo_mqtt_metering-1.0.0-py3-none-any.whl

Download URL aforo_mqtt_metering-1.0.0-py3-none-any.whl
Size 9.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
fcb99a985e73392682a9679aa61e76304e06dfa7b6bdfd6579e3c60a9591f3f9
BLAKE2b-256 checksum
How to use checksums
54145868f38970889ebd03f1b228177f95f2bd9380d9ebf86755782299f84e54
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 1, 2026.

Transparency log

Release history Release notifications | RSS feed

1.2.2

2 release files

This release

1.0.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page