Bitaxe – Pool Difficulty Shows Decimal 12-Digit Precision Bug
Informational — Monitor and address as needed
Symptoms
- AxeOS dashboard `Pool Difficulty` tile renders with 12 decimal places (e.g. `0.000244140625` instead of `0.000244`)
- Pool difficulty appears as `1.000000000000` or `0.062500000000` — full float expansion, not a rounded human number
- Numbers are mathematically correct — `0.000244140625` is exactly `2^-12`, the bug is purely cosmetic
- OLED still shows hashrate climbing, IP unchanged, pool / worker name visible
- Pool dashboard (solo.ckpool.org, public-pool.io, Ocean, Braiins) confirms shares landed in the last 5-10 minutes
- `bestDiff` and `sessionDiff` tiles also render with extra decimals on some firmware builds
- `curl http://<miner-ip>/api/system/info` returns clean numbers — only the *display* layer is misbehaving
- Pattern appeared after a `mining.set_difficulty` event from the pool (low-difficulty solo pool with frequent re-targets is the classic environment)
- No effect on hashrate, share submission cadence, share acceptance, or expected payout
- No effect on `mining.notify` / job processing — only the difficulty *display* is verbose
- Switching pools can change the symptom (some pools send round float values, some send `2^-N` lottery values)
- Restarting the Bitaxe doesn't make the cosmetic change go away — it returns the moment the pool sends another `set_difficulty`
Step-by-Step Fix
Take a deep breath: this is cosmetic only. Before changing anything, confirm via the OLED + your pool's worker dashboard that shares are landing in the last 5-10 minutes. Hashrate is the number that matters; the on-screen difficulty rendering is a label on the wall, not your earnings. If shares are landing on your pool's worker page, your Bitaxe is healthy and this entire page is about a label on the dashboard, not a malfunction.
Hard-refresh AxeOS with `Ctrl`+`Shift`+`R` on Windows/Linux or `Cmd`+`Shift`+`R` on macOS. Forces the browser to drop cached `app.js` chunks and stale front-end render state. Wait 30 seconds for the websocket to repopulate before deciding whether the cosmetic is still there. The first reconnect on a starved task is the slowest one — give it room to settle.
Check your firmware version at `Settings → System → Firmware Version`. Note the exact version string. Cross-check against `https://github.com/bitaxeorg/ESP-Miner/releases`. If you are more than one stable version behind, plan an update — the formatter has shipped fixes multiple times across the last two years and you are likely running on an older render path.
Update firmware via OTA. From AxeOS, `Settings → System → Update Firmware`, point to the latest stable `.bin` for your chip variant, let it run. Stay on strong WiFi during the OTA. After reboot, watch the `Pool Difficulty` tile across one full `mining.set_difficulty` cycle — most cosmetic regressions disappear at this step.
Update firmware via USB-C web-flasher (cleaner). Visit `https://bitaxeorg.github.io/bitaxe-web-flasher/`, pick your variant: `BM1366` = Ultra, `BM1368` = Supra, `BM1370` = Gamma & GT, `BM1397` = Max. Hex uses the multichip fork at `github.com/bitaxeorg/ESP-Miner-multichip`. Connect the USB-C data cable, click `Connect`, hold `BOOT` if prompted, flash. Reconfigure WiFi + pool from the `Bitaxe_xxxx` AP at `http://192.168.4.1/` if the flash erases NVS.
Switch to REST polling for difficulty display. `curl http://<miner-ip>/api/system/info | jq '.poolDifficulty'` returns the value as a clean JSON Number. Pipe through `jq` for formatting, `printf` for human rendering, or read from your favourite monitoring tool. The dashboard tile is convenience; the API is the source of truth. For most operators this is the right architectural choice anyway — your Bitaxe should be monitored from a single REST poller (Home Assistant, Prometheus, a shell script + cron, a Telegram bot), not from N browser tabs streaming websockets.
Build a one-liner difficulty alert: `while true; do curl -s http://<miner-ip>/api/system/info | jq -r '.poolDifficulty' ; sleep 60 ; done` in a tmux pane logs the difficulty cleanly every minute. Cleaner than the dashboard. Easy to redirect to a file for `set_difficulty` history if you want to plot pool behaviour over time. Solo lottery operators love this for understanding their pool's variance — you'll see the difficulty wobble in a way the dashboard hides.
Pin a DHCP reservation for the Bitaxe in your router admin. Find the MAC on the OLED or in the DHCP table and bind it to a fixed IP. Stops the 'IP changed and now my poller is hitting a different device' failure that masquerades as broken display data. Two-minute setup, permanent payoff. Reservation also makes your `curl` one-liners stable across router reboots.
Reboot the Bitaxe and re-observe one full `set_difficulty` cycle. Sometimes the cosmetic only manifests after a specific stratum sequence — a clean reboot lets you see whether the bug appears again on the next pool message or only after an unusual sequence. Pull the barrel / XT30 for 30 seconds, plug back in, wait for OLED hashing, watch the dashboard through the first few `mining.set_difficulty` events. Healthy formatter on current stable should round all of them.
Try a different pool. If the cosmetic only appears on one specific pool's stratum endpoint, you have isolated the trigger: that pool sends exact-binary lottery difficulties. Either accept the display behaviour (firmware is doing the right thing) or switch to a pool that sends rounder values. Production-difficulty pools (Ocean, Braiins, Antpool) send clean integers and won't trigger the cosmetic. Solo pools (`solo.ckpool.org`, `public-pool.io`) typically send the lottery values that look ugly.
Capture the stratum traffic at serial. USB-C data cable, terminal at `115200` baud. Watch the boot log + stratum events as `mining.set_difficulty` arrives. The firmware logs the parsed value; compare it byte-for-byte to what the dashboard renders. If they match exactly, the front-end formatter is not running — open DevTools → Sources, find the dashboard component rendering the `poolDifficulty` field, confirm the formatter function is being called.
Inspect the front-end formatter logic. Open AxeOS dashboard with DevTools → Sources. The Angular components rendering `Pool Difficulty`, `Best Diff`, and `Session Diff` live in `main/http_server/axe-os/src/` in the firmware repo. Look for `Number.toFixed`, `Number.toLocaleString`, or custom rounding helpers — the absence of one is a clean fingerprint for which release introduced the regression. Patch it, rebuild the front-end, OTA-flash. PR upstream so every Bitaxe operator benefits.
Pin to a known-good firmware version if a specific build broke the formatter. The Releases page keeps every signed `.bin`. Re-flash the previous stable via the USB-C web-flasher with the correct chip variant. Document the regression with a GitHub issue: variant, firmware version where the cosmetic appeared, exact value displayed, pool, expected formatted value. Maintainers triage these quickly.
Erase NVS + reflash if formatter weirdness survives a clean firmware update. Web-flasher → `Erase Flash` → reflash → reconfigure from `Bitaxe_xxxx` AP at `http://192.168.4.1/`. A corrupted `nvs` partition can carry stale settings forward across OTA flashes; full erase + reflash is the only way to know you are on a clean slate. Doesn't usually fix cosmetic bugs (those are render-path), but it is a clean baseline for any firmware-side investigation.
File a GitHub issue with reproduction. If the bug genuinely persists on current stable across multiple pools, open an issue at `bitaxeorg/ESP-Miner/issues` with: variant, firmware version, exact pool stratum endpoint, exact value displayed (copy-paste from dashboard), exact value the API returns (copy-paste from `curl`), and the exact `mining.set_difficulty` value from your serial log if you have one. Reproducible cosmetic bugs are easy to fix — provide the maintainer everything needed to reproduce in 60 seconds and the PR usually lands within a release cycle.
You probably don't need professional repair for this. Cosmetic UI bugs are not bench problems — there is no hardware to diagnose. The only reason to escalate to D-Central is if the diagnostic uncovered an *unrelated* hardware fault during investigation: serial log showed brownout traps, ESP32 fails to enumerate over USB-C with `BOOT` held, visible damage near the ESP32 module / USB-C connector / PMIC. In that case book D-Central Bitaxe Repair — bench-level ESP32 diagnostics, JTAG recovery, module replacement if silicon failure, 24-hour burn-in on return.
What D-Central does at the bench (when escalation is real). Bench-level diagnostics: external USB-to-UART for serial when onboard USB is dead, JTAG via the ESP32-S3 debug header, full firmware reflash via `esptool.py` if the web-flasher path is broken, module replacement if the silicon itself is failing, full thermal + voltage burn-in for 24 hours at nameplate. We don't fix `Number.toFixed` bugs at the bench; we fix the hardware issues a cosmetic-investigation might have surfaced.
Ship safely if escalating. Anti-static bag, double-box with ≥ 3 cm foam every side, include a note with: variant, firmware version, the cosmetic display value you observed, the exact API value, the pool you were on, plus *whatever real hardware symptom* led you to ship. If all you have is 'the dashboard shows 12 decimals,' save the shipping cost — refresh the firmware, switch to REST polling, and re-read the diagnostic page.
When to Seek Professional Repair
If the steps above do not resolve the issue, or if you are not comfortable performing these repairs yourself, professional service is recommended. Attempting advanced repairs without proper equipment can cause further damage.
Related Error Codes
Still Having Issues?
Our team of Bitcoin Mining Hackers has been repairing ASIC miners since 2016. We have seen it all and fixed it all. Get a professional diagnosis.
