.
Project description
Python Prometheus Exporters for IoT Devices
Python Prometheus Exporters (pyprom-exporters) is a small Python package that exposes Prometheus
metrics for IoT / smart-home
devices.
The current concrete exporter targets TP-Link Tapo smart plugs via python-kasa.
What It Does
- Discovers Tapo devices on your LAN (UDP broadcast) and/or monitors an explicit list of device IPs.
- Periodically updates device state on a background asyncio loop, with retries and backoff.
- Exposes cached metrics via a Prometheus HTTP endpoint (scrapes do not talk to devices).
How It Works
prom-exporterstarts an asyncio event loop on a background thread.- The Tapo exporter runs discovery, performs an initial update pass, then starts periodic background updates.
- Prometheus scrapes call the exporter
collect()method, which returns cached metric objects. Device I/O happens in the background.
This means the exporter updates devices on its own schedule, not on Prometheus' scrape schedule.
To reduce device/network traffic, set exporters.tapo.prometheus_options.refresh_interval to match
your Prometheus scrape interval (or higher).
The tradeoff is intentional:
- Background polling keeps scrape latency low and predictable.
- Scrapes do not block on device updates and are resilient to transient device timeouts.
Project Layout
src/pyprom_exporters/prom_exporter.py: CLI entry point and runtime wiring.src/pyprom_exporters/config.py: OmegaConf-compatible dataclass configuration models.src/pyprom_exporters/exporters/tapo.py: Tapo smart plug exporter implementation.src/pyprom_exporters/task_collector/async_task_collector.py: async retry runner used for device updates.tests/: unit tests for config/exporter behavior.
Requirements
- Python 3.11+ (uses
asyncio.TaskGroup). - Network reachability from the exporter host to the devices.
- Tapo credentials (provided via env vars or CLI; never written to
config.yaml).
Installation
This repo is set up to use uv and a checked-in uv.lock.
# Development (includes the dev dependency group by default)
uv sync --frozen --group tapo
# Minimal runtime environment
uv sync --frozen --no-dev --group tapo
If you use pip, you must also install python-kasa (it is not part of the base dependencies).
pip install .
pip install python-kasa
Running
- Provide credentials (default env keys):
export TP_LINK_USERNAME="you@example.com"
export TP_LINK_PASSWORD="your-password"
- Run the exporter:
uv run prom-exporter \
--prometheus-port 8090 \
--tapo-plug-devices 10.10.2.100,10.10.2.101
You can also reduce log verbosity:
uv run prom-exporter --log-level WARNING
- Scrape metrics:
http://localhost:8090/metrics
Environment Variable Overrides
The runtime supports a few convenience overrides:
- Precedence: CLI flags override env vars; env vars override
config.yaml. PYPROM_EXPORTERS_LOG_LEVEL(orLOG_LEVEL): overrideslog_level.PROMETHEUS_PORT: overridesprometheus_port.TAPO_PLUG_DEVICES: overridesexporters.tapo.devices(space or comma-separated).TAPO_USERNAME/TAPO_PASSWORD: overrides credentials directly.
Configuration (config.yaml)
prom-exporter reads config.yaml from the working directory.
- If
config.yamldoes not exist, it writes one with defaults. - If
config.yamlexists, it writes back the merged configuration on startup so defaults are explicit. - Credentials are always scrubbed from the written YAML; provide them via env vars or CLI.
write_non_default_config: truewrites only values that differ from defaults.
Important fields:
log_level: root logging level for the process.prometheus_port: exporter listen port.exporters.tapo.devices: list of device IPs to monitor (used in addition to discovery).exporters.tapo.prometheus_options.refresh_interval: background update interval (seconds) and per-device minimum update interval.exporters.tapo.discovery_options.*: discovery parameters passed topython-kasa.exporters.tapo.discovery_options.tapo_username_env_key/tapo_password_env_key: env var names used to populatepython-kasaCredentialsby default.exporters.tapo.supported_device_families: currently onlyPLUG.exporters.tapo.per_device_family_metrics.plug: plug metrics to export.
Discovery note: broadcast discovery generally does not work across VLAN boundaries. If your devices
are on a separate IoT VLAN, set exporters.tapo.devices (or use --tapo-plug-devices) to the
device IPs.
Metrics
The Tapo plug exporter currently emits:
tapo_discovered_devices: number of discovered devices (gauge).current_consumption{host,alias}: watts (gauge).current_voltage{host,alias}: volts (gauge).current_current{host,alias}: amps (gauge).current_consumption_today{host,alias}: watt-hours (gauge).current_month_consumption{host,alias}: watt-hours (gauge).current_rssi{host,alias}: RSSI value reported by the device (gauge).
Only devices that report the current_consumption feature are exported.
Prometheus Scrape Config
Example prometheus.yml:
scrape_configs:
- job_name: pyprom-exporters
static_configs:
- targets: ["<exporter-host>:8090"]
Docker
Build:
docker build -t pyprom-exporters:latest .
Run:
docker run --rm \
-e TP_LINK_USERNAME="you@example.com" \
-e TP_LINK_PASSWORD="your-password" \
-e PROMETHEUS_PORT=8090 \
-e TAPO_PLUG_DEVICES="10.10.2.100,10.10.2.101" \
-p 8090:8090 \
pyprom-exporters:latest
The container entrypoint runs uv run prom-exporter and forwards PROMETHEUS_PORT and
TAPO_PLUG_DEVICES into CLI flags.
Troubleshooting
- No devices discovered:
- Set
exporters.tapo.devices(or use--tapo-plug-devices) instead of relying on broadcast discovery. - Check firewall rules and IoT VLAN routing.
- Set
- Metrics are missing for a device:
- The exporter skips devices that do not report a
current_consumptionfeature.
- The exporter skips devices that do not report a
- Authentication failures:
- Ensure
TP_LINK_USERNAME/TP_LINK_PASSWORD(orTAPO_USERNAME/TAPO_PASSWORD) are set.
- Ensure
Development
# pytest - for tests
uv run pytest
# ruff - for linting and formatting
uv run ruff check .
# format with ruff (or your editor integration)
uv run ruff format .
# pre-commit - for running all configured pre-commit hooks (ruff, isort, etc.)
uv run pre-commit run --all-files
License
Apache-2.0 (see LICENSE).
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
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 pyprom_exporters-0.0.1.tar.gz.
File metadata
- Download URL: pyprom_exporters-0.0.1.tar.gz
- Upload date:
- Size: 101.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1dab7ca53bd1ffb6a42e536a1cc531b0e5c9997277d2a5c074db0c9ee1db8781
|
|
| MD5 |
3c276598008201d334528f5122355f26
|
|
| BLAKE2b-256 |
bf569bbb75c41f1667dcc4c69d2732b6ae9ec552386f9f8c3a8b3a876bc8970d
|
Provenance
The following attestation bundles were made for pyprom_exporters-0.0.1.tar.gz:
Publisher:
release.yml on andylamp/pyprom-exporters
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pyprom_exporters-0.0.1.tar.gz -
Subject digest:
1dab7ca53bd1ffb6a42e536a1cc531b0e5c9997277d2a5c074db0c9ee1db8781 - Sigstore transparency entry: 975821027
- Sigstore integration time:
-
Permalink:
andylamp/pyprom-exporters@b26b105f57483d6f3c2f27b3f075f1866bb73020 -
Branch / Tag:
refs/heads/release - Owner: https://github.com/andylamp
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@b26b105f57483d6f3c2f27b3f075f1866bb73020 -
Trigger Event:
push
-
Statement type:
File details
Details for the file pyprom_exporters-0.0.1-py3-none-any.whl.
File metadata
- Download URL: pyprom_exporters-0.0.1-py3-none-any.whl
- Upload date:
- Size: 22.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2e379efbba552d39e77625eb05f4307d1a2eb60671fb021949a546a73b2e3e34
|
|
| MD5 |
173a327613f20bb28a963e343ca8ff72
|
|
| BLAKE2b-256 |
6591ee09a896d07c1a161cc968dec771f00bb968a55857ed317fee61faac7608
|
Provenance
The following attestation bundles were made for pyprom_exporters-0.0.1-py3-none-any.whl:
Publisher:
release.yml on andylamp/pyprom-exporters
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pyprom_exporters-0.0.1-py3-none-any.whl -
Subject digest:
2e379efbba552d39e77625eb05f4307d1a2eb60671fb021949a546a73b2e3e34 - Sigstore transparency entry: 975821029
- Sigstore integration time:
-
Permalink:
andylamp/pyprom-exporters@b26b105f57483d6f3c2f27b3f075f1866bb73020 -
Branch / Tag:
refs/heads/release - Owner: https://github.com/andylamp
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@b26b105f57483d6f3c2f27b3f075f1866bb73020 -
Trigger Event:
push
-
Statement type: