bambulab-metrics-exporter

bambulab-metrics-exporter

Docker app from BlackBush's Repository

Overview

Prometheus exporter for Bambu Lab printers on Unraid. Exposes /metrics, /health, and /ready. Quick setup: 1) Set required values: BAMBULAB_TRANSPORT, BAMBULAB_SERIAL, BAMBULAB_SECRET_KEY (example: openssl rand -base64 48). 2) cloud_mqtt: set BAMBULAB_CLOUD_EMAIL (code/token fields can be left empty for first run and may auto-populate). 3) local_mqtt: set BAMBULAB_HOST and BAMBULAB_ACCESS_CODE. Then start the container and open WebUI for status. Scrape /metrics from Prometheus.

bambulab-metrics-exporter

Python 3.11 GitHub Release Docker Publish GHCR Package Ko-fi

Production-oriented Prometheus exporter for Bambu Lab printers (homelab/self-hosted friendly).

Note: Development and real-world validation of this exporter are currently done only on an X1C printer. If you want to help improve support for additional printer models, please get in touch with me via GitHub.


Docs / Wiki

Full operator documentation lives in the GitHub Wiki.

Page Description
Quick Start Get up and running in under 5 minutes
Installation Docker, Docker Compose, Unraid, GHCR
Configuration Full environment variable reference
Prometheus Setup Scrape config, job examples
Metrics Reference All metrics, PromQL examples
Grafana Dashboard Import steps, panel list, alert rules — also on Grafana.com
Troubleshooting Common issues and debugging steps

Table of contents

What this does

  • Connects to Bambu printer over LAN MQTT (default) or Cloud MQTT
  • Periodically requests a full state snapshot (pushall)
  • Parses print state/telemetry into stable Prometheus metrics
  • Exposes:
    • GET / — landing page with version and status
    • GET /metrics
    • GET /health
    • GET /ready

Implementation notes

  • Supports both LAN MQTT (local_mqtt) and Cloud MQTT (cloud_mqtt).
  • Uses device/<serial>/report and device/<serial>/request topics.
  • Requests full snapshots with pushall and maps stable telemetry fields to Prometheus metrics.
  • Printer model detection uses a table-driven resolver pipeline (product_namehw_ver+project_nameSN prefix → legacy fallbacks), including newer SN prefixes such as 22E (P2S), 093 (H2S), and 094 (H2D).

Deployment: This project is deployed via Docker. There is no pip/PyPI distribution. See Installation for full setup instructions.

Quick start

# Pull and run (Local mode — printer must be on same LAN)
docker run -d \
  --name bambulab-exporter \
  -p 9109:9109 \
  -e BAMBULAB_HOST=192.168.1.100 \
  -e BAMBULAB_SERIAL=01P00A000000000 \
  -e BAMBULAB_ACCESS_CODE=12345678 \
  ghcr.io/theblackbush/bambulab_metrics_exporter:latest

Or with an env file:

cp .env.example .env
# edit .env with your values
docker run -d --name bambulab-exporter -p 9109:9109 --env-file .env \
  ghcr.io/theblackbush/bambulab_metrics_exporter:latest

Then verify:

curl http://localhost:9109/health
curl http://localhost:9109/metrics | grep bambulab_printer_connected

For a step-by-step walkthrough see Quick Start in the Wiki.

Local mode vs Cloud mode

The exporter supports two transport modes. local_mqtt is the default — no extra configuration needed if your printer is on the same LAN.

Mode BAMBULAB_TRANSPORT When to use
Local mode (default) local_mqtt (or omit) Printer is on your LAN and LAN Mode is enabled
Cloud mode cloud_mqtt Printer is not directly reachable (remote, CGNAT, etc.)

Local mode — required vars:

BAMBULAB_HOST=192.168.1.100
BAMBULAB_SERIAL=01P00A000000000
BAMBULAB_ACCESS_CODE=12345678

Cloud mode — required vars:

BAMBULAB_TRANSPORT=cloud_mqtt
BAMBULAB_SERIAL=01P00A000000000
BAMBULAB_SECRET_KEY=<openssl rand -hex 32>
BAMBULAB_CLOUD_EMAIL=you@example.com

See Configuration for the full variable reference.

Cloud authentication

Cloud credentials are obtained via the bambulab-cloud-auth CLI bundled in the container image. No local Python installation is required.

Container-native OTP flow (recommended)

  1. Set BAMBULAB_CLOUD_EMAIL in your .env. Do not set BAMBULAB_CLOUD_CODE yet.
  2. Start the container. It detects no valid credentials, sends a verification code to your Bambu account email, and exits.
  3. Check your email for the code.
  4. Add BAMBULAB_CLOUD_CODE=<code> to .env and restart the container.
  5. The container authenticates, stores encrypted credentials to the config volume, and starts normally.
  6. Remove BAMBULAB_CLOUD_CODE from .env — codes are single-use; it is not needed for normal operation.

On every subsequent restart, stored credentials are loaded automatically.

BAMBULAB_CLOUD_CODE lifecycle

BAMBULAB_CLOUD_CODE is a one-time bootstrap variable. It is needed again only if:

  • Stored credentials are missing or cleared (fresh config volume, accidental deletion).
  • The Bambu Cloud session expired or account password changed.
  • BAMBULAB_SECRET_KEY was changed — the encrypted credential file can no longer be decrypted.

In any of these cases, start the container without BAMBULAB_CLOUD_CODE to trigger a new code delivery, then follow steps 3–6 above.

For the manual bambulab-cloud-auth flow and full credential lifecycle details, see Installation and Quick Start.

Environment variables

Variable Required Default Description
BAMBULAB_TRANSPORT no local_mqtt Transport backend (local_mqtt or cloud_mqtt)
BAMBULAB_HOST yes (local) - Printer IP/hostname
BAMBULAB_PORT no 8883 Printer MQTT TLS port
BAMBULAB_SERIAL yes - Printer serial/device id
BAMBULAB_ACCESS_CODE yes (local) - Printer LAN access code
BAMBULAB_USERNAME no bblp MQTT username
BAMBULAB_REQUEST_PUSHALL no true Request full snapshot every poll
BAMBULAB_SECRET_KEY yes (cloud) - Encrypts stored cloud credentials — keep stable
BAMBULAB_CLOUD_EMAIL yes (cloud) - Bambu account email for OTP flow
BAMBULAB_CLOUD_CODE bootstrap only - One-time OTP code; remove after first auth
BAMBULAB_CLOUD_USER_ID no - Cloud user id (if already obtained)
BAMBULAB_CLOUD_ACCESS_TOKEN no - Cloud access token (if already obtained)
BAMBULAB_CLOUD_MQTT_HOST no us.mqtt.bambulab.com Cloud MQTT broker
BAMBULAB_CLOUD_MQTT_PORT no 8883 Cloud MQTT port
PRINTER_NAME_LABEL no empty Custom printer name label (falls back to BAMBULAB_PRINTER_NAME)
BAMBULAB_PRINTER_NAME no auto Real printer name discovered from machine (auto-persisted)
POLLING_INTERVAL_SECONDS no 10 Polling interval
REQUEST_TIMEOUT_SECONDS no 8 Per-cycle snapshot timeout
LISTEN_HOST no 0.0.0.0 HTTP bind host
LISTEN_PORT no 9109 HTTP port
LOG_LEVEL no INFO Python log level

Full reference including PUID/PGID/UMASK and advanced options: Configuration.

Docker

GHCR pre-built image (recommended)

docker run -d --name bambulab-exporter -p 9109:9109 --env-file .env \
  ghcr.io/theblackbush/bambulab_metrics_exporter:latest

Docker Compose

docker compose up -d

The included docker-compose.yml is cloud-first and minimal by default. Required cloud fields are active; optional fields are commented with inline hints. Works for Linux hosts and Unraid (PUID/PGID/UMASK optional).

Build locally

docker build -t bambulab-metrics-exporter:latest .
docker run -d --name bambulab-exporter -p 9109:9109 --env-file .env \
  bambulab-metrics-exporter:latest

Unraid

A ready-to-import template is included: unraid-bambulab-metrics-exporter.xml

  1. Docker → Add Container → Template — paste XML content or use Template URL.
  2. Fill in BAMBULAB_SECRET_KEY and required transport fields.
  3. Start container and verify /metrics.

See Installation for full Unraid and PUID/PGID setup.

Prometheus integration

Use examples/prometheus/prometheus.scrape.yml snippet, or equivalent:

scrape_configs:
  - job_name: bambulab
    scrape_interval: 15s
    metrics_path: /metrics
    static_configs:
      - targets: ["bambulab-metrics-exporter:9109"]

See Prometheus Setup for full scrape config, alerting rules, and recording rules.

Operator PromQL examples

AMS metrics

  • Average humidity index per AMS unit over 15 minutes:
avg_over_time(bambulab_ams_unit_humidity_index{printer_name="$printer"}[15m])
  • Lowest remaining filament percentage per printer (all AMS slots):
min by (printer_name) (bambulab_ams_slot_remaining_percent)
  • Slots below 15% remaining filament:
bambulab_ams_slot_remaining_percent{printer_name="$printer"} < 15

Alert tuning examples

  • Door open while printing, less sensitive (require 2 minutes open):
bambulab_door_open{printer_name="$printer"} == 1
and on(printer_name, serial)
bambulab_printer_gcode_state{printer_name="$printer", state="RUNNING"} == 1

Suggested alert rule tuning:

for: 2m
labels:
  severity: warning
  • Stale exporter threshold tuned for slower polling environments:
time() - bambulab_exporter_last_success_unixtime{printer_name="$printer"} > 300

Suggested alert rule tuning:

for: 2m
labels:
  severity: warning
  • SD card abnormal status:
bambulab_sdcard_status_info{printer_name="$printer", status="abnormal"} == 1

More PromQL examples and alert rules: Metrics Reference and Grafana Dashboard.

Exported metrics (core)

Metric Type Description
bambulab_printer_up Gauge 1 if latest poll returned a valid payload.
bambulab_printer_connected Gauge 1 if MQTT connection is up.
bambulab_print_progress_percent Gauge Print progress percent.
bambulab_print_remaining_seconds Gauge Estimated seconds remaining.
bambulab_print_layer_current Gauge Current print layer.
bambulab_print_layer_total Gauge Total print layers.
bambulab_print_layer_progress_percent Gauge Layer-based progress percent.
bambulab_nozzle_temperature_celsius Gauge Current nozzle temperature.
bambulab_nozzle_target_temperature_celsius Gauge Target nozzle temperature.
bambulab_nozzle_diameter Gauge Nozzle diameter from telemetry.
bambulab_bed_temperature_celsius Gauge Current bed temperature.
bambulab_bed_target_temperature_celsius Gauge Target bed temperature.
bambulab_chamber_temperature_celsius Gauge Chamber temperature.
bambulab_fan_big_1_speed_percent Gauge Big fan 1 speed percent.
bambulab_fan_big_2_speed_percent Gauge Big fan 2 speed percent.
bambulab_fan_cooling_speed_percent Gauge Cooling fan speed percent.
bambulab_fan_heatbreak_speed_percent Gauge Heatbreak fan speed percent.
bambulab_fan_secondary_aux_speed_percent Gauge Secondary auxiliary fan speed percent from print.device.airduct.parts[id=160].
bambulab_printer_error Gauge 1 when printer error code is non-zero.
bambulab_printer_error_code Gauge Raw printer error code (mc_print_error_code).
bambulab_print_error_code Gauge Raw print_error value from MQTT (legacy alias).
bambulab_print_error Gauge Raw print_error value from MQTT.
bambulab_ap_error_code Gauge Raw ap_err value from MQTT.
bambulab_printer_gcode_state{state} One-hot Gauge Current gcode state as one-hot labels.
bambulab_subtask_name_info{subtask_name} Info Gauge Current subtask name.
bambulab_fail_reason_info{fail_reason} Info Gauge Current fail reason.
bambulab_printer_model_info{model} Info Gauge Detected printer model.
bambulab_wifi_signal Gauge Wi-Fi signal value (dBm when available).
bambulab_online_ahb Gauge Online AHB flag.
bambulab_online_ext Gauge Online external flag.
bambulab_chamber_light_on Gauge Chamber light status (1/0).
bambulab_work_light_on Gauge Work light status (1/0).
bambulab_xcam_feature_enabled{feature} Gauge XCam feature enable flags.
bambulab_xcam_halt_print_sensitivity_info{level} Info Gauge XCam halt-print sensitivity level (low/medium/high).
bambulab_ams_status_id Gauge AMS status numeric code.
bambulab_ams_status_name{status} Info Gauge AMS status name label.
bambulab_ams_rfid_status_id Gauge AMS RFID status numeric code.
bambulab_ams_rfid_status_name{status} Info Gauge AMS RFID status name label.
bambulab_ams_unit_info{ams_id,ams_model,ams_series} Info Gauge AMS unit identity labels.
bambulab_ams_unit_humidity{ams_id} Gauge AMS humidity raw value.
bambulab_ams_unit_humidity_index{ams_id} Gauge AMS humidity index (1-5).
bambulab_ams_unit_temperature_celsius{ams_id} Gauge AMS temperature.
bambulab_ams_slot_active{ams_id,slot_id} Gauge AMS slot active flag.
bambulab_ams_slot_remaining_percent{ams_id,slot_id} Gauge AMS slot remaining filament %.
bambulab_ams_slot_tray_info{ams_id,slot_id,tray_type,tray_color} Info Gauge AMS slot filament type and color.
bambulab_ams_heater_state_info{ams_id,ams_model,ams_series,state} Info Gauge Gen2 AMS heater/dry state.
bambulab_ams_dry_fan_status{ams_id,ams_model,ams_series,fan_id} Gauge Gen2 AMS drying fan status.
bambulab_ams_dry_sub_status_info{ams_id,ams_model,ams_series,state} Info Gauge Gen2 AMS drying sub-status.
bambulab_external_spool_active Gauge 1 when external spool is active.
bambulab_external_spool_info{external_id,tray_type,tray_info_idx,tray_color} Info Gauge External spool metadata.
bambulab_active_extruder_index Gauge Active extruder index (dual-extruder models).
bambulab_extruder_temperature_celsius{extruder_id} Gauge Per-extruder current temperature.
bambulab_extruder_target_temperature_celsius{extruder_id} Gauge Per-extruder target temperature.
bambulab_extruder_nozzle_info{extruder_id,nozzle_type,nozzle_diameter} Info Gauge Per-extruder nozzle metadata.
bambulab_active_nozzle_info{nozzle_type,nozzle_diameter} Info Gauge Active nozzle metadata.
bambulab_hotend_rack_holder_position_info{position} Info Gauge Hotend rack holder position.
bambulab_hotend_rack_holder_state_info{state} Info Gauge Hotend rack holder state.
bambulab_hotend_rack_slot_state_info{slot_id,state} Info Gauge Hotend rack slot state (mounted/docked/empty).
bambulab_hotend_rack_hotend_info{slot_id,nozzle_type,nozzle_diameter} Info Gauge Hotend rack slot nozzle metadata.
bambulab_hotend_rack_hotend_wear_ratio{slot_id} Gauge Hotend rack nozzle wear ratio.
bambulab_hotend_rack_hotend_runtime_minutes{slot_id} Gauge Hotend rack nozzle runtime minutes.
bambulab_sdcard_status_info{status} Info Gauge SD-card status (present/abnormal/absent).
bambulab_door_open Gauge Door open flag.
bambulab_lid_open Gauge Lid open flag (H2 family via stat bit 24, or direct lid_open).
bambulab_wired_network Gauge Wired network detected flag.
bambulab_camera_recording Gauge Camera recording flag.
bambulab_ams_auto_switch Gauge AMS auto-switch flag.
bambulab_filament_tangle_detected Gauge Filament tangle detected flag.
bambulab_filament_tangle_detect_supported Gauge Filament tangle detection support flag.
bambulab_queue_total Gauge Total queued jobs.
bambulab_queue_estimated_seconds Gauge Estimated queue seconds.
bambulab_queue_number Gauge Queue number.
bambulab_queue_status Gauge Queue status numeric code.
bambulab_queue_position Gauge Queue position.
bambulab_spd_lvl Gauge Speed level numeric value.
bambulab_spd_mag Gauge Speed multiplier/percentage.
bambulab_spd_lvl_state{mode} One-hot Gauge Speed mode one-hot labels.
bambulab_stg_cur Gauge Current stage numeric id.
bambulab_print_stage_info{stage} Info Gauge Current stage name label.
bambulab_exporter_scrape_duration_seconds Gauge Duration of last scrape cycle.
bambulab_exporter_scrape_success Gauge 1 when last scrape succeeded.
bambulab_exporter_last_success_unixtime Gauge Unix timestamp of last successful scrape.

All metrics include stable labels:

  • printer_name (from PRINTER_NAME_LABEL or BAMBULAB_PRINTER_NAME)
  • serial (from BAMBULAB_SERIAL)

Migration note (stage metrics)

  • bambulab_mc_print_stage_state{stage} was removed.
  • Use bambulab_print_stage_info{stage} for stage labels and bambulab_stg_cur for numeric stage IDs.

Testing

pip install -r requirements-dev.txt
# or: pip install -e .[dev]
pytest --cov=src --cov-report=term-missing

Maintaining >90% test coverage for core modules.

Test command profiles

make test              # full suite with coverage gate
make test-unit         # unit suite with coverage gate
make test-integration  # integration-only (runs with --no-cov)
make test-e2e          # e2e-only (runs with --no-cov)
make test-profile      # deterministic smoke profile (integration + e2e)

Why --no-cov for integration/e2e-only runs? The project enforces a global coverage threshold in default pytest options, so subset-only runs use --no-cov to avoid false negatives unrelated to test correctness.

Sample payload and expected metrics

  • MQTT sample payload: examples/sample_mqtt_message.json
  • Sample metrics excerpt: examples/sample_metrics.prom

These are useful for quick regression checks and dashboard/query validation.

Known limitations

  1. Cloud mode requires a valid access token (a helper tool is included for obtaining it).
  2. TLS cert verification is disabled in both LAN/cloud MQTT paths for compatibility with current broker behavior.
  3. Some firmware fields can be missing or model-specific; exporter degrades gracefully (NaN for missing scalar values).

Future enhancements

  • Automatic access-token refresh using refresh token
  • Optional job-name metric via controlled allow-listing (avoid cardinality issues)
  • Better fan mapping per model/firmware
  • Integration tests with recorded MQTT fixtures

Dashboard Preview

The dashboard is available on the Grafana.com dashboard listing.

Grafana Dashboard Sample

Install bambulab-metrics-exporter on Unraid in a few clicks.

Find bambulab-metrics-exporter in Community Apps on your Unraid server, review the template, and click Install. Unraid handles the Docker app or plugin setup from the published template.

Open the Apps tab on your Unraid server Search Community Apps for bambulab-metrics-exporter Review the template variables and paths Click Install

Related apps

Details

Repository
ghcr.io/theblackbush/bambulab_metrics_exporter:latest
Last Updated2026-07-18
First Seen2026-03-30

Runtime arguments

Web UI
http://[IP]:[PORT:9109]/
Network
bridge
Shell
sh
Privileged
false

Template configuration

Web UI PortPorttcp

Exporter HTTP port

Target
9109
Default
9109
Value
9109
Config DirPathrw

Persistent config and encrypted credentials

Target
/config/bambulab-metrics-exporter
Default
/mnt/user/appdata/bambulab-metrics-exporter
Value
/mnt/user/appdata/bambulab-metrics-exporter
Listen HostVariable

HTTP bind host

Target
LISTEN_HOST
Default
0.0.0.0
Value
0.0.0.0
Listen PortVariable

HTTP bind port

Target
LISTEN_PORT
Default
9109
Value
9109
TransportVariable

Select transport mode

Target
BAMBULAB_TRANSPORT
Default
cloud_mqtt|local_mqtt
Value
cloud_mqtt
Printer SerialVariable

Printer device serial (required)

Target
BAMBULAB_SERIAL
Secret KeyVariable

Strong key for encrypted credentials. Generate example: openssl rand -base64 48

Target
BAMBULAB_SECRET_KEY
Cloud EmailVariable

Used only when Transport=cloud_mqtt. Recommended/required for automatic cloud auth flow.

Target
BAMBULAB_CLOUD_EMAIL
Cloud One-Time CodeVariable

Used only when Transport=cloud_mqtt. Optional verification code from email; if empty, startup can trigger code flow and ask for restart.

Target
BAMBULAB_CLOUD_CODE
Cloud User IDVariable

Used only when Transport=cloud_mqtt. Usually auto-filled by startup auth process; can stay empty on first run.

Target
BAMBULAB_CLOUD_USER_ID
Cloud Access TokenVariable

Used only when Transport=cloud_mqtt. Usually auto-filled by startup auth process; leave empty unless setting manually.

Target
BAMBULAB_CLOUD_ACCESS_TOKEN
Cloud Refresh TokenVariable

Used only when Transport=cloud_mqtt. Auto-filled when available by startup auth process; optional for manual setup.

Target
BAMBULAB_CLOUD_REFRESH_TOKEN
Cloud MQTT HostVariable

Cloud MQTT host

Target
BAMBULAB_CLOUD_MQTT_HOST
Default
us.mqtt.bambulab.com
Value
us.mqtt.bambulab.com
Cloud MQTT PortVariable

Cloud MQTT port

Target
BAMBULAB_CLOUD_MQTT_PORT
Default
8883
Value
8883
Local Host/IPVariable

Used only when Transport=local_mqtt. Required printer IP/hostname.

Target
BAMBULAB_HOST
Local Access CodeVariable

Used only when Transport=local_mqtt. Required LAN access code from printer settings.

Target
BAMBULAB_ACCESS_CODE
Local MQTT PortVariable

Used only when Transport=local_mqtt. Usually keep default 8883.

Target
BAMBULAB_PORT
Default
8883
Value
8883
Local MQTT UsernameVariable

Used only when Transport=local_mqtt. Usually keep default bblp.

Target
BAMBULAB_USERNAME
Default
bblp
Value
bblp
PUIDVariable

User ID to run container as (Unraid: usually 99)

Default
99
Value
99
PGIDVariable

Group ID to run container as (Unraid: usually 100)

Default
100
Value
100
UMASKVariable

File creation mask

Default
002
Value
002
Config Dir EnvVariable

Internal config path

Target
BAMBULAB_CONFIG_DIR
Default
/config/bambulab-metrics-exporter
Value
/config/bambulab-metrics-exporter
Credentials FileVariable

Encrypted credentials filename

Target
BAMBULAB_CREDENTIALS_FILE
Default
credentials.enc.json
Value
credentials.enc.json
Polling IntervalVariable

Polling interval in seconds

Target
POLLING_INTERVAL_SECONDS
Default
10
Value
10
Request TimeoutVariable

Request timeout in seconds

Target
REQUEST_TIMEOUT_SECONDS
Default
8
Value
8
Log LevelVariable

DEBUG/INFO/WARNING/ERROR

Target
LOG_LEVEL
Default
INFO
Value
INFO
Printer Name LabelVariable

Prometheus label value; leave empty to auto-fill from printer serial

Target
PRINTER_NAME