Avalon Home Prometheus Exporter v0.3.1
Table of Contents
Avalon Home Prometheus Exporter v0.3.1
I shipped v0.3.1 of avalonhome-prometheus-exporter, my small Prometheus exporter for Avalon Home-series ASIC miners.
The short version: it talks to Avalon miners over the CGMiner TCP API, turns the weird little pile of miner telemetry into Prometheus metrics, and gives you something sane to graph in Grafana. Hashrate, temperatures, fans, share stats, pool status, hardware errors, scrape health, firmware info, and optional chip-level telemetry are all exposed from a single /metrics endpoint.
It currently targets the Avalon Nano 3S and Mini 3, but it should be useful for other Avalon Home-series miners that speak the same CGMiner API dialect.
Also, important disclosure: I vibe-coded the shit out of this with ChatGPT and Claude. It is still a pure Python, standard-library-only, single-file exporter. No Prometheus client dependency, no framework, no package-manager nonsense. Just Docker, an environment file, and some TCP socket wrangling.
Why I Built It
I wanted proper monitoring for the little Avalon miners on my network. The built-in interfaces are fine for a quick glance, but I wanted history: hashrate over time, temperature trends, fan behavior, rejected shares, pool status, and whether a miner was actually down or just quietly lying to me by showing stale values somewhere in a dashboard.
Prometheus and Grafana are already how I watch the rest of my homelab, so the answer was obvious: make the miners speak Prometheus.
The exporter polls the miner API with a combined CGMiner command:
version+summary+stats+config+devs+devdetails+poolsThen it parses the response and emits metrics with the avalon_ prefix. Nothing fancy, but it works.
What’s in v0.3.1
This is mostly a correctness and polish release. Not glamorous, but the kind of release that makes the tool less annoying to run for real.
Incomplete CGMiner responses are now rejected. Previously, a malformed or partial response could be treated as a successful scrape. That’s bad monitoring hygiene. If the miner gives us garbage, the exporter now calls it garbage instead of pretending everything is fine.
Session-wide pool percentage metrics got clearer names. The session-level pool rejected/stale percentages are now:
avalon_session_pool_rejected_percent
avalon_session_pool_stale_percentThe existing per-pool metrics stay where they belong:
avalon_pool_rejected_percent
avalon_pool_stale_percentIf your Grafana panels are using the per-pool metrics, you should not need to change anything. If you were intentionally using the old unlabeled session-wide values, switch to the new avalon_session_pool_* names.
Docker healthchecks now honor custom exporter ports. If you changed EXPORTER_PORT, the container healthcheck follows it now. Revolutionary stuff: checking the port you actually configured.
Bad numeric environment values now fail cleanly. Invalid values for things like ports, intervals, and timeouts go through the normal config validation path, with clear errors instead of ugly surprises.
HTTP requests are served concurrently. A slow /metrics or /debug client no longer blocks /health. This matters when Prometheus is scraping, you’re debugging, and Docker or an orchestrator is also trying to decide whether the container is alive.
The Grafana dashboard export has been replaced. The included dashboard JSON is now a valid sanitized schema v2 export. The previous one was not in the shape it needed to be. Annoying, but fixed.
Docs and naming got cleaned up. The troubleshooting commands now match the current Compose service name, the v0.3.x health output, and the gated /debug endpoint. The Compose service/container naming is standardized on avalonhome-exporter.
The Useful Bits
The exporter gives you a few categories of metrics that I care about most:
avalon_upand scrape error counters, so you know whether the exporter can actually talk to the mineravalon_hashrate_ghs,avalon_hashrate_moving_ghs, andavalon_hashrate_avg_ghs, because watching mining performance is the whole pointavalon_temp_*_celsiusandavalon_fan*_rpm, because tiny ASICs are basically space heaters with Ethernet- pool metrics with pool labels, so you can see where accepted/rejected/stale shares are coming from
avalon_info{...}, which carries model, firmware, hardware type, MAC, DNA, and other static identity bits as labels- optional chip telemetry behind
EXPORT_CHIP_METRICS=true, for when you want the firehose and accept the cardinality hit
The default setup keeps chip metrics off. That’s intentional. Per-chip series are useful when debugging, but I don’t need Prometheus storing every little bit of chip telemetry forever just because I got curious at 11 PM.
Running It
Docker Compose is the easiest path:
git clone https://github.com/brav0charlie/avalonhome-prometheus-exporter.git
cd avalonhome-prometheus-exporter
cp .env.example .env
# edit .env with your miner IP or IPs
docker compose up -dThen point Prometheus at the exporter:
scrape_configs:
- job_name: "avalon"
scrape_interval: 30s
static_configs:
- targets:
- "exporter-host:9100"Health and version endpoints are there too:
http://localhost:9100/health
http://localhost:9100/versionThe /debug endpoint exists, but it is disabled by default and has to be explicitly enabled with ENABLE_DEBUG_ENDPOINT=true, because dumping internal state from a monitoring endpoint should not be an accidental footgun.
Release Links
If you’re running Avalon Home miners and already have Prometheus/Grafana around, this should be enough to get actual observability instead of periodically clicking through a miner web UI like it’s 2009.