Repository navigation
Releases: SerpentXSF/Dual-Pool-Mining-NerdAxe-BitAxe
Release list
SerpentX-DualPool-1.8 - NerdAxe finally gets a web UI asset
Adds a NerdAxe web UI asset, which this project has never shipped. Dual-pool mining is unchanged, and the BitAxe firmware is unchanged since 1.7.
New asset: www-nerdaxe.bin
A release carries both firmwares, so they cannot both ship a file called www.bin. Until now the only www.bin in a release was the BitAxe one, which meant a NerdAxe had no web UI asset at all, and flashing the one that was there would install the BitAxe interface over NerdOS.
Simply adding the file would not have been enough: the NerdAxe upload rejected anything not named exactly www.bin, so every user would have had to rename the file they had just downloaded. So the manual website upload now accepts www.bin, www-nerdaxe.bin, and any www-<tag>.bin. The pattern is anchored, so evil-www.bin, www.bin.txt and esp-miner.bin are still refused.
NerdAxe devices on 1.4 or earlier still enforce the exact name. Update the firmware first, then the web UI, or rename the file by hand once.
Versions
| version | ||
|---|---|---|
| BitAxe (AxeOS) | SerpentX-DualPool-1.8 |
unchanged from 1.7 apart from the version string |
| NerdAxe (NerdOS) | SerpentX-DualPool-1.5 |
accepts the new web UI asset name |
The release tag follows the BitAxe version. The two firmwares carry their own version strings because they move independently.
If the dashboard says the versions do not match
After flashing www.bin on a BitAxe you may see:
Firmware (…) and AxeOS (…) versions do not match. Please make sure to update both www.bin and esp-miner.bin.
Restart the device and it clears. The AxeOS version is read from inside the web UI partition exactly once, during startup, and flashing the web UI does not reboot. Until the next restart the device keeps reporting the version it read at boot, from the previous UI. Nothing is actually mismatched and no reflashing is needed.
Updating
BitAxe: esp-miner.bin then www.bin. NerdAxe: esp-miner-nerdaxe.bin or esp-miner-NerdAxeGamma.bin, then www-nerdaxe.bin. The esp-miner-factory*.bin images are for a full serial flash of a blank board.
Restart after updating. On NerdOS this matters for more than the version display: a device comes back from an OTA running appreciably slow and stays that way until it is explicitly restarted, and nothing in the API reports it.
A full-erase web flash wipes the board provisioning held in NVS and the device will not come up correctly afterwards. On a device already running, OTA is the safe path.
Every app binary in this release was verified to appear byte for byte inside its matching factory image, so the two cannot be from different builds.
SerpentX-DualPool-1.7 - a Pool A outage no longer kills Pool B
Simultaneous dual-pool mining is unchanged. This release exists because two real dual-pool bugs have been sitting fixed-but-unreleased since 1.6 was cut in August, so anyone still on 1.6 is running with both of them.
Fixed: a Pool A outage took Pool B down with it
The worst of the two. When every configured pool stopped answering, the firmware would stop mining and drop the ASIC to 0V to conserve power. That is correct for a single-pool miner. On a dual-pool miner it was not: Pool B could be perfectly healthy and still get killed, because the power-down decision never asked whether the second pool was still delivering work.
Mining now only stops when there is nothing left to mine for. The fan controller had to learn the same thing in the same change, because the two read that state independently and a mismatch would have left the ASIC running at full load with the fan dropped to 30%.
Reproduced and verified on hardware: with Pool A and its fallback both blackholed for seven minutes, the log showed the pool-failure path being entered and the device still mining Pool B throughout, with no ASIC shutdown.
Fixed: Pool B corrupted Pool A's stratum timing table
Both pools were writing into one shared send-timestamp table keyed by message id. Pool B's submissions overwrote Pool A's entries, so Pool A's reported stratum response times were wrong whenever both pools were active. Share submission itself was unaffected; the damage was to the numbers you would use to judge a pool. Pool B now does not stamp the table at all, which is the honest fix since there was only ever one table.
Also
- Each pool gets its own ASIC job slots. This was done expecting a throughput gain and there was no measured gain, so it ships as a correctness/clarity change rather than a performance one.
chipsDetectedandasicCountare now both reported from/api/system/info, on BitAxe and NerdAxe. A miner that comes up with an ASIC missing used to look completely healthy, showing the configured chip count and a hashrate that was quietly some fraction low. It is the disagreement between configured and detected that carries the signal, which is why both are reported together.
Versions in this release
| version | ||
|---|---|---|
| BitAxe (AxeOS) | SerpentX-DualPool-1.7 |
all four changes above |
| NerdAxe (NerdOS) | SerpentX-DualPool-1.4 |
the chipsDetected change |
The two firmwares carry their own version strings because they move independently. NerdAxe gets a bump rather than shipping changed code under the string that already shipped as 1.3.
Updating
Use the device's own update path with esp-miner.bin (BitAxe) or esp-miner-nerdaxe.bin / esp-miner-NerdAxeGamma.bin (NerdAxe), plus www.bin for the web UI. The esp-miner-factory*.bin images are for a full serial flash of a blank board.
A full-erase web flash wipes the board provisioning held in NVS and the device will not come up correctly afterwards. On a device that is already running, OTA is the safe path.
The BitAxe OTA binary in this release is the exact artifact verified on hardware. The factory images are those same artifacts merged with the bootloader, partition table and (for BitAxe) the NVS provisioning blob; they were built but not separately flashed to a blank board.
SerpentX-DualPool-1.6 - websocket fixes, faster logging, job-ID measurement
Everything since 1.2, verified on live hardware. BitAxe firmware is 1.6; NerdAxe/NerdAxeGamma firmware is 1.3 (that firmware did not change in the later rounds - its binaries here are the current ones).
Important
If your miner is on 1.2 and you used Settings -> Release & Update, that panel
was previously offering 1.2 as "latest" because no newer release had been cut.
This release fixes that. Update from here, or via the web flasher.
The headline fix: the dashboard was lying to you
/api/ws/live accepted websocket connections and then never sent a single byte.
Root cause: as of ESP-IDF 5.5 the URI handler is not invoked for a websocket
handshake at all (httpd_uri.c returns early), and this fork did all of its client
registration inside that handler. So no client was ever registered, the push task
stayed in its "no clients" hibernate path, and the socket went mute.
The browser could not tell - esp_http_server answers the handshake itself - so the
dashboard saw a healthy socket, switched off its own HTTP polling, and then
reported "Unable to reach the device" while the miner was mining perfectly.
Fixed by registering from ws_post_handshake_cb, and the web UI no longer trusts an
open socket: it polls unless data is genuinely arriving.
Also in this release
- Websocket admission moved ahead of the handshake. Refusals are now a real
401/429instead of a completed handshake that is silently dropped. The client
cap was previously not even observable - 14 connections would all "succeed"
against a limit of 10. - Send hardening - the broadcast path validates that an fd is still an active
websocket before writing, closing a window where a recycled socket could receive
stray frames. - Non-blocking UART logging (upstream ESP-Miner #1889) - log writes no longer
block inside the logging path. Upstream measured job processing dropping from
121.79 ms to 2.15 ms; that matters more here, because this fork switches pools on
a timer and the blocking write sat inside that critical section. - New telemetry on
/api/system/info:logDroppedBytes, plusjobIdSeenPoolA/B,
jobIdDupPoolA/B,jobIdCrossPoolandjobIdSkipped- measurement used to decide,
with data rather than assumption, whether upstream's global duplicate-job filter
would be safe for a miner running two pools at once. tools/fleet_check.py- fleet health check that verifies frames actually
arrive on the live websocket, not merely that it connects. A connect-only test
would have missed the bug above entirely.- NerdAxe/Quad: the same websocket pattern is future-proofed against a later
ESP-IDF bump, with a build guard so it cannot regress silently.
Which file do I want?
| Device | Full flash (at 0x0) |
OTA firmware | OTA web UI |
|---|---|---|---|
| BitAxe (BM1370 Gamma) | esp-miner-factory.bin |
esp-miner.bin |
www.bin |
| NerdAxe (BM1366) | esp-miner-factory-nerdaxe.bin |
esp-miner-nerdaxe.bin |
www.bin |
| NerdAxe Gamma (BM1370) | esp-miner-factory-nerdaxegamma.bin |
esp-miner-NerdAxeGamma.bin |
www.bin |
OTA is the recommended path. A full-erase web flash wipes the NVS board
provisioning and can leave the device boot-looping; the factory images include that
provisioning, but OTA avoids the issue entirely.
SerpentX-DualPool-1.2
Dual-pool firmware for BitAxe and NerdAxe (BM1366 / BM1370 Gamma).
What's new in 1.2
- Web UI cache fix: API responses send
Cache-Control: no-storeand unmatched/api/*returns a clean JSON 404 (fixes blank / stuck "Loading..." in Chrome after a flash). - In-UI update panel now pulls from this repo (was pointing at upstream): the Settings "Release & Update" section lists our releases and installs our firmware.
Which file to use
- BitAxe: web-flash
esp-miner-factory.bin, or from AxeOS Settings downloadesp-miner.bin+www.binand upload them. - NerdAxe (BM1366):
esp-miner-factory-nerdaxe.bin(or Settings > Install from GitHub). - NerdAxe Gamma (BM1370):
esp-miner-factory-nerdaxegamma.bin(or Settings > Install from GitHub).
V5 - SerpentX Dual Pool Mining (full source)
SerpentX Dual Pool Mining — source release (UI refresh over V4).
Changes since V4
- BitAxe web UI: the header now shows the original AxeOS mark stacked above the SerpentX wordmark (AxeOS enlarged, wordmark trimmed). UI-only — the mining firmware is unchanged from V4, so you can update the look with an OTA "Web UI" upload of
www.bin(no reflash).
Feature set (unchanged from V4)
- True simultaneous dual-pool mining — two Stratum sessions time-sliced on a configurable interval, hashrate split by ratio; per-pool failover; custom per-pool password.
- BitAxe: 3000 ms default split interval (field-tuned), live-tunable interval/ratio, efficiency + reconnect-window hardening, SerpentX AxeOS UI (accent-colour picker, visible dashboard resize grip).
- NerdAxe / NerdQAxe: native dual-pool (Pool Mode = Dual + Pool Balance slider).
Flashing
- Factory images (attached) flash at offset
0x0via the localFlasher/tool oresptool. - BitAxe UI-only update: OTA the attached
www.bin(Web UI). - Prebuilt OTA files + SHA-256 sums are in
Firmware-Binaries/.
Hardware note
Fixed-function SHA-256d ASICs — both pools must be SHA-256d / Bitcoin-header pools; total hashrate is split, not doubled.
V4 — SerpentX Dual Pool Mining (full source)
SerpentX Dual Pool Mining — first full-source release.
main now carries the complete source for all three device families plus prebuilt images. (The earlier V2/V3 tags remain the packaged-zip releases.)
Features
- True simultaneous dual-pool mining — two permanently-connected Stratum sessions, time-sliced on a configurable interval, with the ASIC's hashrate split between them by a set ratio (not failover; both pools mine at once).
- Custom per-pool password — saved to NVS and sent to
mining.authorize. - Dedicated per-pool failover — each pool has its own primary/failover endpoint and fails over independently.
BitAxe highlights in this drop
- Default Split Interval 3000 ms (field-tuned — 500 ms drove the ASIC error rate up).
- Live-tunable interval / ratio / enable — no reboot.
- Efficiency + stability: pool-aware
clean_jobs, A→B slice donation, drain-to-newest, Pool B reconnect-window hardening, version-mask coherence. - SerpentX AxeOS UI — header wordmark, top-right accent-colour picker, visible dashboard resize grip.
NerdAxe / NerdQAxe
Dual-pool is native (Pool Mode = Dual + Pool Balance slider) — no custom firmware required.
Flashing
- Factory images (attached) flash at offset
0x0via the localFlasher/web tool oresptool. - Already running? Update over the air (Firmware + Web UI). Prebuilt OTA files and SHA-256 sums are in
Firmware-Binaries/.
Hardware note
These boards use fixed-function SHA-256d ASICs — both pools must be SHA-256d / Bitcoin-header pools, and total hashrate is split, not doubled.
Revision 3
Minor improvements to the template cadence and the following.
- Fixed the high error rate on the miners — traced it to the dual-pool switch cadence, changed the default Split Interval from 500 ms → 3000 ms (your field test: one miner dropped from ~20% to ~3%), and made interval/ratio/enable live-tunable with no reboot.
- Ran a Fable review and fixed the real share loss — a Pool A clean_jobs was silently killing Pool B's in-flight jobs on the shared ASIC job ring; added pool-aware clean_jobs, A→B slice donation (mine Pool B instead of idling when Pool A is down), drain-to-newest, plus a poolBStaleDrops diagnostic and a dropped-share recovery backstop.
- Confirmed the "error rate" is the ASIC hardware counter (not a software share metric) and documented the pool-vs-local troubleshooting heuristic; also mapped which fixes are BitAxe-only (NerdAxe/NerdQAxe use native upstream dual-pool, unchanged).
- Branded the BitAxe web UI as SerpentX — header wordmark, a top-right accent-color picker (default AxeOS Blue, browser-saved), and made the dashboard widget resize grip visible; rebuilt www.bin (firmware untouched).
- Spun off a separate "Dual Pool Proxy" session to build a ckpool-based external dual-pool proxy (for closed miners like Hammer), and assessed that Hammer's firmware is closed/LTC so only the proxy route is viable.
Revision 2
Includes the maintenance/error-rate hardening: live-tunable Split Interval/ratio/dual-enable (no reboot), Pool B version-mask coherence, dropped-share recovery (a sub-difficulty nonce whose job slot was reused across pools is re-tested against the other live templates and submitted to the pool that owns it), and a default Split Interval of 3000 ms (field-tested: 500 ms → 3000 ms took one miner's error rate from ~20% to ~3%).