diff --git a/docs/generate_miners.py b/docs/generate_miners.py index cf3ea670..87f23886 100644 --- a/docs/generate_miners.py +++ b/docs/generate_miners.py @@ -49,6 +49,8 @@ def backend_str(backend: MinerTypes) -> str: return "LuxOS Firmware Miners" case MinerTypes.MARATHON: return "Mara Firmware Miners" + case MinerTypes.BITAXE: + return "Stock Firmware BitAxe Miners" def create_url_str(mtype: str): diff --git a/docs/miners/antminer/X15.md b/docs/miners/antminer/X15.md index 8fbb1c26..9c6b9073 100644 --- a/docs/miners/antminer/X15.md +++ b/docs/miners/antminer/X15.md @@ -1,7 +1,7 @@ # pyasic ## X15 Models -## Z15 +## Z15 (Stock) ::: pyasic.miners.antminer.cgminer.X15.Z15.CGMinerZ15 handler: python options: diff --git a/docs/miners/antminer/X17.md b/docs/miners/antminer/X17.md index b60db7b8..4dfe6072 100644 --- a/docs/miners/antminer/X17.md +++ b/docs/miners/antminer/X17.md @@ -1,49 +1,49 @@ # pyasic ## X17 Models -## S17 +## S17 (Stock) ::: pyasic.miners.antminer.bmminer.X17.S17.BMMinerS17 handler: python options: show_root_heading: false heading_level: 4 -## S17+ +## S17+ (Stock) ::: pyasic.miners.antminer.bmminer.X17.S17.BMMinerS17Plus handler: python options: show_root_heading: false heading_level: 4 -## S17 Pro +## S17 Pro (Stock) ::: pyasic.miners.antminer.bmminer.X17.S17.BMMinerS17Pro handler: python options: show_root_heading: false heading_level: 4 -## S17e +## S17e (Stock) ::: pyasic.miners.antminer.bmminer.X17.S17.BMMinerS17e handler: python options: show_root_heading: false heading_level: 4 -## T17 +## T17 (Stock) ::: pyasic.miners.antminer.bmminer.X17.T17.BMMinerT17 handler: python options: show_root_heading: false heading_level: 4 -## T17+ +## T17+ (Stock) ::: pyasic.miners.antminer.bmminer.X17.T17.BMMinerT17Plus handler: python options: show_root_heading: false heading_level: 4 -## T17e +## T17e (Stock) ::: pyasic.miners.antminer.bmminer.X17.T17.BMMinerT17e handler: python options: diff --git a/docs/miners/antminer/X19.md b/docs/miners/antminer/X19.md index 11c7fbdf..f01ba1ba 100644 --- a/docs/miners/antminer/X19.md +++ b/docs/miners/antminer/X19.md @@ -1,224 +1,231 @@ # pyasic ## X19 Models -## S19 +## S19 (Stock) ::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19 handler: python options: show_root_heading: false heading_level: 4 -## S19L +## S19L (Stock) ::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19L handler: python options: show_root_heading: false heading_level: 4 -## S19 Pro +## S19 Pro (Stock) ::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19Pro handler: python options: show_root_heading: false heading_level: 4 -## S19j +## S19j (Stock) ::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19j handler: python options: show_root_heading: false heading_level: 4 -## S19i +## S19i (Stock) ::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19i handler: python options: show_root_heading: false heading_level: 4 -## S19+ +## S19+ (Stock) ::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19Plus handler: python options: show_root_heading: false heading_level: 4 -## S19j No PIC +## S19j No PIC (Stock) ::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19jNoPIC handler: python options: show_root_heading: false heading_level: 4 -## S19 Pro+ +## S19 Pro+ (Stock) ::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19ProPlus handler: python options: show_root_heading: false heading_level: 4 -## S19j Pro +## S19j Pro (Stock) ::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19jPro handler: python options: show_root_heading: false heading_level: 4 -## S19 XP +## S19 XP (Stock) ::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19XP handler: python options: show_root_heading: false heading_level: 4 -## S19a +## S19a (Stock) ::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19a handler: python options: show_root_heading: false heading_level: 4 -## S19a Pro +## S19a Pro (Stock) ::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19aPro handler: python options: show_root_heading: false heading_level: 4 -## S19 Hydro +## S19 Hydro (Stock) ::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19Hydro handler: python options: show_root_heading: false heading_level: 4 -## S19 Pro Hydro +## S19 Pro Hydro (Stock) ::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19ProHydro handler: python options: show_root_heading: false heading_level: 4 -## S19 Pro+ Hydro +## S19 Pro+ Hydro (Stock) ::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19ProPlusHydro handler: python options: show_root_heading: false heading_level: 4 -## S19K Pro +## S19K Pro (Stock) ::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19KPro handler: python options: show_root_heading: false heading_level: 4 -## T19 +## T19 (Stock) ::: pyasic.miners.antminer.bmminer.X19.T19.BMMinerT19 handler: python options: show_root_heading: false heading_level: 4 -## S19 +## S19 (BOS+) ::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19 handler: python options: show_root_heading: false heading_level: 4 -## S19+ +## S19+ (BOS+) ::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19Plus handler: python options: show_root_heading: false heading_level: 4 -## S19 Pro +## S19 Pro (BOS+) ::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19Pro handler: python options: show_root_heading: false heading_level: 4 -## S19a +## S19a (BOS+) ::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19a handler: python options: show_root_heading: false heading_level: 4 -## S19a Pro +## S19a Pro (BOS+) ::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19aPro handler: python options: show_root_heading: false heading_level: 4 -## S19j +## S19j (BOS+) ::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19j handler: python options: show_root_heading: false heading_level: 4 -## S19j No PIC +## S19j No PIC (BOS+) ::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19jNoPIC handler: python options: show_root_heading: false heading_level: 4 -## S19j Pro +## S19j Pro (BOS+) ::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19jPro handler: python options: show_root_heading: false heading_level: 4 -## S19j Pro No PIC +## S19j Pro No PIC (BOS+) ::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19jProNoPIC handler: python options: show_root_heading: false heading_level: 4 -## S19j Pro+ +## S19j Pro+ (BOS+) ::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19jProPlus handler: python options: show_root_heading: false heading_level: 4 -## S19j Pro+ +## S19j Pro+ (BOS+) ::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19jProPlus handler: python options: show_root_heading: false heading_level: 4 -## S19j Pro+ No PIC +## S19j Pro+ No PIC (BOS+) ::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19jProPlusNoPIC handler: python options: show_root_heading: false heading_level: 4 -## S19k Pro No PIC +## S19k Pro No PIC (BOS+) ::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19kProNoPIC handler: python options: show_root_heading: false heading_level: 4 -## S19 XP +## S19k Pro No PIC (BOS+) +::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19kProNoPIC + handler: python + options: + show_root_heading: false + heading_level: 4 + +## S19 XP (BOS+) ::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19XP handler: python options: show_root_heading: false heading_level: 4 -## T19 +## T19 (BOS+) ::: pyasic.miners.antminer.bosminer.X19.T19.BOSMinerT19 handler: python options: diff --git a/docs/miners/antminer/X21.md b/docs/miners/antminer/X21.md index 39fcff04..fc7539d8 100644 --- a/docs/miners/antminer/X21.md +++ b/docs/miners/antminer/X21.md @@ -1,27 +1,34 @@ # pyasic ## X21 Models -## S21 +## S21 (Stock) ::: pyasic.miners.antminer.bmminer.X21.S21.BMMinerS21 handler: python options: show_root_heading: false heading_level: 4 -## T21 +## T21 (Stock) ::: pyasic.miners.antminer.bmminer.X21.T21.BMMinerT21 handler: python options: show_root_heading: false heading_level: 4 -## S21 +## S21 (BOS+) ::: pyasic.miners.antminer.bosminer.X21.S21.BOSMinerS21 handler: python options: show_root_heading: false heading_level: 4 +## S21 (VNish) +::: pyasic.miners.antminer.vnish.X21.S21.VNishS21 + handler: python + options: + show_root_heading: false + heading_level: 4 + ## S21 (ePIC) ::: pyasic.miners.antminer.epic.X21.S21.ePICS21 handler: python diff --git a/docs/miners/antminer/X3.md b/docs/miners/antminer/X3.md index b3695dd9..5ca2d80d 100644 --- a/docs/miners/antminer/X3.md +++ b/docs/miners/antminer/X3.md @@ -1,21 +1,21 @@ # pyasic ## X3 Models -## D3 +## D3 (Stock) ::: pyasic.miners.antminer.cgminer.X3.D3.CGMinerD3 handler: python options: show_root_heading: false heading_level: 4 -## HS3 +## HS3 (Stock) ::: pyasic.miners.antminer.bmminer.X3.HS3.BMMinerHS3 handler: python options: show_root_heading: false heading_level: 4 -## L3+ +## L3+ (Stock) ::: pyasic.miners.antminer.bmminer.X3.L3.BMMinerL3Plus handler: python options: diff --git a/docs/miners/antminer/X5.md b/docs/miners/antminer/X5.md index deb33a89..944f4b05 100644 --- a/docs/miners/antminer/X5.md +++ b/docs/miners/antminer/X5.md @@ -1,7 +1,7 @@ # pyasic ## X5 Models -## DR5 +## DR5 (Stock) ::: pyasic.miners.antminer.cgminer.X5.DR5.CGMinerDR5 handler: python options: diff --git a/docs/miners/antminer/X7.md b/docs/miners/antminer/X7.md index ea532304..7bccd093 100644 --- a/docs/miners/antminer/X7.md +++ b/docs/miners/antminer/X7.md @@ -1,7 +1,7 @@ # pyasic ## X7 Models -## L7 +## L7 (Stock) ::: pyasic.miners.antminer.bmminer.X7.L7.BMMinerL7 handler: python options: diff --git a/docs/miners/antminer/X9.md b/docs/miners/antminer/X9.md index 6a69d0df..0fda0313 100644 --- a/docs/miners/antminer/X9.md +++ b/docs/miners/antminer/X9.md @@ -1,35 +1,35 @@ # pyasic ## X9 Models -## E9Pro +## E9Pro (Stock) ::: pyasic.miners.antminer.bmminer.X9.E9.BMMinerE9Pro handler: python options: show_root_heading: false heading_level: 4 -## S9 +## S9 (Stock) ::: pyasic.miners.antminer.bmminer.X9.S9.BMMinerS9 handler: python options: show_root_heading: false heading_level: 4 -## S9i +## S9i (Stock) ::: pyasic.miners.antminer.bmminer.X9.S9.BMMinerS9i handler: python options: show_root_heading: false heading_level: 4 -## S9j +## S9j (Stock) ::: pyasic.miners.antminer.bmminer.X9.S9.BMMinerS9j handler: python options: show_root_heading: false heading_level: 4 -## T9 +## T9 (Stock) ::: pyasic.miners.antminer.bmminer.X9.T9.BMMinerT9 handler: python options: @@ -43,7 +43,7 @@ show_root_heading: false heading_level: 4 -## T9 (Hive) +## T9 (Stock) ::: pyasic.miners.antminer.hiveon.X9.T9.HiveonT9 handler: python options: diff --git a/docs/miners/auradine/AD.md b/docs/miners/auradine/AD.md index 08f9db64..e3ec74a6 100644 --- a/docs/miners/auradine/AD.md +++ b/docs/miners/auradine/AD.md @@ -1,21 +1,21 @@ # pyasic ## AD Models -## AT1500 +## AT1500 (Stock) ::: pyasic.miners.auradine.flux.AD.AT1.AuradineFluxAT1500 handler: python options: show_root_heading: false heading_level: 4 -## AT2860 +## AT2860 (Stock) ::: pyasic.miners.auradine.flux.AD.AT2.AuradineFluxAT2860 handler: python options: show_root_heading: false heading_level: 4 -## AT2880 +## AT2880 (Stock) ::: pyasic.miners.auradine.flux.AD.AT2.AuradineFluxAT2880 handler: python options: diff --git a/docs/miners/auradine/AI.md b/docs/miners/auradine/AI.md index 6a05a788..d237658d 100644 --- a/docs/miners/auradine/AI.md +++ b/docs/miners/auradine/AI.md @@ -1,14 +1,14 @@ # pyasic ## AI Models -## AI2500 +## AI2500 (Stock) ::: pyasic.miners.auradine.flux.AI.AI2.AuradineFluxAI2500 handler: python options: show_root_heading: false heading_level: 4 -## AI3680 +## AI3680 (Stock) ::: pyasic.miners.auradine.flux.AI.AI3.AuradineFluxAI3680 handler: python options: diff --git a/docs/miners/auradine/AT.md b/docs/miners/auradine/AT.md index 1081b21f..d49c54ae 100644 --- a/docs/miners/auradine/AT.md +++ b/docs/miners/auradine/AT.md @@ -1,14 +1,14 @@ # pyasic ## AT Models -## AD2500 +## AD2500 (Stock) ::: pyasic.miners.auradine.flux.AT.AD2.AuradineFluxAD2500 handler: python options: show_root_heading: false heading_level: 4 -## AD3500 +## AD3500 (Stock) ::: pyasic.miners.auradine.flux.AT.AD3.AuradineFluxAD3500 handler: python options: diff --git a/docs/miners/avalonminer/A10X.md b/docs/miners/avalonminer/A10X.md index 60f9bb81..bdc91f72 100644 --- a/docs/miners/avalonminer/A10X.md +++ b/docs/miners/avalonminer/A10X.md @@ -1,21 +1,21 @@ # pyasic ## A10X Models -## Avalon 1026 +## Avalon 1026 (Stock) ::: pyasic.miners.avalonminer.cgminer.A10X.A1026.CGMinerAvalon1026 handler: python options: show_root_heading: false heading_level: 4 -## Avalon 1047 +## Avalon 1047 (Stock) ::: pyasic.miners.avalonminer.cgminer.A10X.A1047.CGMinerAvalon1047 handler: python options: show_root_heading: false heading_level: 4 -## Avalon 1066 +## Avalon 1066 (Stock) ::: pyasic.miners.avalonminer.cgminer.A10X.A1066.CGMinerAvalon1066 handler: python options: diff --git a/docs/miners/avalonminer/A11X.md b/docs/miners/avalonminer/A11X.md index 4624b2f4..c51ebc87 100644 --- a/docs/miners/avalonminer/A11X.md +++ b/docs/miners/avalonminer/A11X.md @@ -1,7 +1,7 @@ # pyasic ## A11X Models -## Avalon 1166 Pro +## Avalon 1166 Pro (Stock) ::: pyasic.miners.avalonminer.cgminer.A11X.A1166.CGMinerAvalon1166Pro handler: python options: diff --git a/docs/miners/avalonminer/A12X.md b/docs/miners/avalonminer/A12X.md index 0a8429a0..644d65e4 100644 --- a/docs/miners/avalonminer/A12X.md +++ b/docs/miners/avalonminer/A12X.md @@ -1,7 +1,7 @@ # pyasic ## A12X Models -## Avalon 1246 +## Avalon 1246 (Stock) ::: pyasic.miners.avalonminer.cgminer.A12X.A1246.CGMinerAvalon1246 handler: python options: diff --git a/docs/miners/avalonminer/A7X.md b/docs/miners/avalonminer/A7X.md index b2c8371c..f760417f 100644 --- a/docs/miners/avalonminer/A7X.md +++ b/docs/miners/avalonminer/A7X.md @@ -1,21 +1,21 @@ # pyasic ## A7X Models -## Avalon 721 +## Avalon 721 (Stock) ::: pyasic.miners.avalonminer.cgminer.A7X.A721.CGMinerAvalon721 handler: python options: show_root_heading: false heading_level: 4 -## Avalon 741 +## Avalon 741 (Stock) ::: pyasic.miners.avalonminer.cgminer.A7X.A741.CGMinerAvalon741 handler: python options: show_root_heading: false heading_level: 4 -## Avalon 761 +## Avalon 761 (Stock) ::: pyasic.miners.avalonminer.cgminer.A7X.A761.CGMinerAvalon761 handler: python options: diff --git a/docs/miners/avalonminer/A8X.md b/docs/miners/avalonminer/A8X.md index 7e99dcba..b0a34c3d 100644 --- a/docs/miners/avalonminer/A8X.md +++ b/docs/miners/avalonminer/A8X.md @@ -1,21 +1,21 @@ # pyasic ## A8X Models -## Avalon 821 +## Avalon 821 (Stock) ::: pyasic.miners.avalonminer.cgminer.A8X.A821.CGMinerAvalon821 handler: python options: show_root_heading: false heading_level: 4 -## Avalon 841 +## Avalon 841 (Stock) ::: pyasic.miners.avalonminer.cgminer.A8X.A841.CGMinerAvalon841 handler: python options: show_root_heading: false heading_level: 4 -## Avalon 851 +## Avalon 851 (Stock) ::: pyasic.miners.avalonminer.cgminer.A8X.A851.CGMinerAvalon851 handler: python options: diff --git a/docs/miners/avalonminer/A9X.md b/docs/miners/avalonminer/A9X.md index 1af53274..c2b0acca 100644 --- a/docs/miners/avalonminer/A9X.md +++ b/docs/miners/avalonminer/A9X.md @@ -1,7 +1,7 @@ # pyasic ## A9X Models -## Avalon 921 +## Avalon 921 (Stock) ::: pyasic.miners.avalonminer.cgminer.A9X.A921.CGMinerAvalon921 handler: python options: diff --git a/docs/miners/bitaxe/BM.md b/docs/miners/bitaxe/BM.md new file mode 100644 index 00000000..fe0bfbf3 --- /dev/null +++ b/docs/miners/bitaxe/BM.md @@ -0,0 +1,24 @@ +# pyasic +## BM Models + +## Supra (Stock) +::: pyasic.miners.bitaxe.espminer.BM.BM1368.BitAxeSupra + handler: python + options: + show_root_heading: false + heading_level: 4 + +## Ultra (Stock) +::: pyasic.miners.bitaxe.espminer.BM.BM1366.BitAxeUltra + handler: python + options: + show_root_heading: false + heading_level: 4 + +## Max (Stock) +::: pyasic.miners.bitaxe.espminer.BM.BM1397.BitAxeMax + handler: python + options: + show_root_heading: false + heading_level: 4 + diff --git a/docs/miners/blockminer/blockminer.md b/docs/miners/blockminer/blockminer.md new file mode 100644 index 00000000..715be9e2 --- /dev/null +++ b/docs/miners/blockminer/blockminer.md @@ -0,0 +1,17 @@ +# pyasic +## blockminer Models + +## BlockMiner 520i (ePIC) +::: pyasic.miners.blockminer.epic.blockminer.blockminer.ePICBlockMiner520i + handler: python + options: + show_root_heading: false + heading_level: 4 + +## BlockMiner 720i (ePIC) +::: pyasic.miners.blockminer.epic.blockminer.blockminer.ePICBlockMiner720i + handler: python + options: + show_root_heading: false + heading_level: 4 + diff --git a/docs/miners/goldshell/X5.md b/docs/miners/goldshell/X5.md index 8ca83002..f4d77c6b 100644 --- a/docs/miners/goldshell/X5.md +++ b/docs/miners/goldshell/X5.md @@ -1,21 +1,21 @@ # pyasic ## X5 Models -## CK5 +## CK5 (Stock) ::: pyasic.miners.goldshell.bfgminer.X5.CK5.GoldshellCK5 handler: python options: show_root_heading: false heading_level: 4 -## HS5 +## HS5 (Stock) ::: pyasic.miners.goldshell.bfgminer.X5.HS5.GoldshellHS5 handler: python options: show_root_heading: false heading_level: 4 -## KD5 +## KD5 (Stock) ::: pyasic.miners.goldshell.bfgminer.X5.KD5.GoldshellKD5 handler: python options: diff --git a/docs/miners/goldshell/XBox.md b/docs/miners/goldshell/XBox.md index 263ed930..d483ba8b 100644 --- a/docs/miners/goldshell/XBox.md +++ b/docs/miners/goldshell/XBox.md @@ -1,14 +1,14 @@ # pyasic ## XBox Models -## KD Box II +## KD Box II (Stock) ::: pyasic.miners.goldshell.bfgminer.XBox.KDBox.GoldshellKDBoxII handler: python options: show_root_heading: false heading_level: 4 -## KD Box Pro +## KD Box Pro (Stock) ::: pyasic.miners.goldshell.bfgminer.XBox.KDBox.GoldshellKDBoxPro handler: python options: diff --git a/docs/miners/goldshell/XMax.md b/docs/miners/goldshell/XMax.md index 0533a633..8b0953f7 100644 --- a/docs/miners/goldshell/XMax.md +++ b/docs/miners/goldshell/XMax.md @@ -1,7 +1,7 @@ # pyasic ## XMax Models -## KD Max +## KD Max (Stock) ::: pyasic.miners.goldshell.bfgminer.XMax.KDMax.GoldshellKDMax handler: python options: diff --git a/docs/miners/innosilicon/A10X.md b/docs/miners/innosilicon/A10X.md index 8319625f..c81ccfeb 100644 --- a/docs/miners/innosilicon/A10X.md +++ b/docs/miners/innosilicon/A10X.md @@ -1,7 +1,7 @@ # pyasic ## A10X Models -## A10X +## A10X (Stock) ::: pyasic.miners.innosilicon.cgminer.A10X.A10X.InnosiliconA10X handler: python options: diff --git a/docs/miners/innosilicon/T3X.md b/docs/miners/innosilicon/T3X.md index 15e4f8fb..b81af696 100644 --- a/docs/miners/innosilicon/T3X.md +++ b/docs/miners/innosilicon/T3X.md @@ -1,7 +1,7 @@ # pyasic ## T3X Models -## T3H+ +## T3H+ (Stock) ::: pyasic.miners.innosilicon.cgminer.T3X.T3H.InnosiliconT3HPlus handler: python options: diff --git a/docs/miners/supported_types.md b/docs/miners/supported_types.md index dcd0280e..27cd9120 100644 --- a/docs/miners/supported_types.md +++ b/docs/miners/supported_types.md @@ -18,78 +18,78 @@ details {
X3 Series:
X5 Series:
X7 Series:
X9 Series:
X15 Series:
X17 Series:
X19 Series:
X21 Series:
@@ -100,234 +100,234 @@ details {
M2X Series:
M3X Series:
M5X Series:
M6X Series:
@@ -338,43 +338,43 @@ details {
A7X Series:
A8X Series:
A9X Series:
A10X Series:
A11X Series:
A12X Series:
@@ -385,13 +385,13 @@ details {
T3X Series:
A10X Series:
@@ -402,22 +402,22 @@ details {
X5 Series:
XMax Series:
XBox Series:
@@ -446,27 +446,28 @@ details {
X19 Series:
X21 Series:
@@ -507,6 +508,12 @@ details {
  • T19 (VNish)
  • +
    + X21 Series: + +
    @@ -546,7 +553,7 @@ details {
    X9 Series:
    @@ -586,23 +593,23 @@ details {
    AD Series:
    AI Series:
    AT Series:
    @@ -630,4 +637,17 @@ details {
    + +
    +Stock Firmware BitAxe Miners: +
    \ No newline at end of file diff --git a/docs/miners/whatsminer/M2X.md b/docs/miners/whatsminer/M2X.md index 2cae2ddc..0724c495 100644 --- a/docs/miners/whatsminer/M2X.md +++ b/docs/miners/whatsminer/M2X.md @@ -1,91 +1,91 @@ # pyasic ## M2X Models -## M20 V10 +## M20 V10 (Stock) ::: pyasic.miners.whatsminer.btminer.M2X.M20.BTMinerM20V10 handler: python options: show_root_heading: false heading_level: 4 -## M20S V10 +## M20S V10 (Stock) ::: pyasic.miners.whatsminer.btminer.M2X.M20S.BTMinerM20SV10 handler: python options: show_root_heading: false heading_level: 4 -## M20S V20 +## M20S V20 (Stock) ::: pyasic.miners.whatsminer.btminer.M2X.M20S.BTMinerM20SV20 handler: python options: show_root_heading: false heading_level: 4 -## M20S V30 +## M20S V30 (Stock) ::: pyasic.miners.whatsminer.btminer.M2X.M20S.BTMinerM20SV30 handler: python options: show_root_heading: false heading_level: 4 -## M20P V10 +## M20P V10 (Stock) ::: pyasic.miners.whatsminer.btminer.M2X.M20P.BTMinerM20PV10 handler: python options: show_root_heading: false heading_level: 4 -## M20P V30 +## M20P V30 (Stock) ::: pyasic.miners.whatsminer.btminer.M2X.M20P.BTMinerM20PV30 handler: python options: show_root_heading: false heading_level: 4 -## M20S+ V30 +## M20S+ V30 (Stock) ::: pyasic.miners.whatsminer.btminer.M2X.M20S_Plus.BTMinerM20SPlusV30 handler: python options: show_root_heading: false heading_level: 4 -## M21 V10 +## M21 V10 (Stock) ::: pyasic.miners.whatsminer.btminer.M2X.M21.BTMinerM21V10 handler: python options: show_root_heading: false heading_level: 4 -## M21S V20 +## M21S V20 (Stock) ::: pyasic.miners.whatsminer.btminer.M2X.M21S.BTMinerM21SV20 handler: python options: show_root_heading: false heading_level: 4 -## M21S V60 +## M21S V60 (Stock) ::: pyasic.miners.whatsminer.btminer.M2X.M21S.BTMinerM21SV60 handler: python options: show_root_heading: false heading_level: 4 -## M21S V70 +## M21S V70 (Stock) ::: pyasic.miners.whatsminer.btminer.M2X.M21S.BTMinerM21SV70 handler: python options: show_root_heading: false heading_level: 4 -## M21S+ V20 +## M21S+ V20 (Stock) ::: pyasic.miners.whatsminer.btminer.M2X.M21S_Plus.BTMinerM21SPlusV20 handler: python options: show_root_heading: false heading_level: 4 -## M29 V10 +## M29 V10 (Stock) ::: pyasic.miners.whatsminer.btminer.M2X.M29.BTMinerM29V10 handler: python options: diff --git a/docs/miners/whatsminer/M3X.md b/docs/miners/whatsminer/M3X.md index a060b1f5..01f1e7d7 100644 --- a/docs/miners/whatsminer/M3X.md +++ b/docs/miners/whatsminer/M3X.md @@ -1,1008 +1,1008 @@ # pyasic ## M3X Models -## M30 V10 +## M30 V10 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30.BTMinerM30V10 handler: python options: show_root_heading: false heading_level: 4 -## M30 V20 +## M30 V20 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30.BTMinerM30V20 handler: python options: show_root_heading: false heading_level: 4 -## M30K V10 +## M30K V10 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30K.BTMinerM30KV10 handler: python options: show_root_heading: false heading_level: 4 -## M30L V10 +## M30L V10 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30L.BTMinerM30LV10 handler: python options: show_root_heading: false heading_level: 4 -## M30S V10 +## M30S V10 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S.BTMinerM30SV10 handler: python options: show_root_heading: false heading_level: 4 -## M30S V20 +## M30S V20 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S.BTMinerM30SV20 handler: python options: show_root_heading: false heading_level: 4 -## M30S V30 +## M30S V30 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S.BTMinerM30SV30 handler: python options: show_root_heading: false heading_level: 4 -## M30S V40 +## M30S V40 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S.BTMinerM30SV40 handler: python options: show_root_heading: false heading_level: 4 -## M30S V50 +## M30S V50 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S.BTMinerM30SV50 handler: python options: show_root_heading: false heading_level: 4 -## M30S V60 +## M30S V60 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S.BTMinerM30SV60 handler: python options: show_root_heading: false heading_level: 4 -## M30S V70 +## M30S V70 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S.BTMinerM30SV70 handler: python options: show_root_heading: false heading_level: 4 -## M30S V80 +## M30S V80 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S.BTMinerM30SV80 handler: python options: show_root_heading: false heading_level: 4 -## M30S VE10 +## M30S VE10 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S.BTMinerM30SVE10 handler: python options: show_root_heading: false heading_level: 4 -## M30S VE20 +## M30S VE20 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S.BTMinerM30SVE20 handler: python options: show_root_heading: false heading_level: 4 -## M30S VE30 +## M30S VE30 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S.BTMinerM30SVE30 handler: python options: show_root_heading: false heading_level: 4 -## M30S VE40 +## M30S VE40 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S.BTMinerM30SVE40 handler: python options: show_root_heading: false heading_level: 4 -## M30S VE50 +## M30S VE50 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S.BTMinerM30SVE50 handler: python options: show_root_heading: false heading_level: 4 -## M30S VE60 +## M30S VE60 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S.BTMinerM30SVE60 handler: python options: show_root_heading: false heading_level: 4 -## M30S VE70 +## M30S VE70 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S.BTMinerM30SVE70 handler: python options: show_root_heading: false heading_level: 4 -## M30S VF10 +## M30S VF10 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S.BTMinerM30SVF10 handler: python options: show_root_heading: false heading_level: 4 -## M30S VF20 +## M30S VF20 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S.BTMinerM30SVF20 handler: python options: show_root_heading: false heading_level: 4 -## M30S VF30 +## M30S VF30 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S.BTMinerM30SVF30 handler: python options: show_root_heading: false heading_level: 4 -## M30S VG10 +## M30S VG10 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S.BTMinerM30SVG10 handler: python options: show_root_heading: false heading_level: 4 -## M30S VG20 +## M30S VG20 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S.BTMinerM30SVG20 handler: python options: show_root_heading: false heading_level: 4 -## M30S VG30 +## M30S VG30 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S.BTMinerM30SVG30 handler: python options: show_root_heading: false heading_level: 4 -## M30S VG40 +## M30S VG40 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S.BTMinerM30SVG40 handler: python options: show_root_heading: false heading_level: 4 -## M30S VH10 +## M30S VH10 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S.BTMinerM30SVH10 handler: python options: show_root_heading: false heading_level: 4 -## M30S VH20 +## M30S VH20 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S.BTMinerM30SVH20 handler: python options: show_root_heading: false heading_level: 4 -## M30S VH30 +## M30S VH30 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S.BTMinerM30SVH30 handler: python options: show_root_heading: false heading_level: 4 -## M30S VH40 +## M30S VH40 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S.BTMinerM30SVH40 handler: python options: show_root_heading: false heading_level: 4 -## M30S VH50 +## M30S VH50 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S.BTMinerM30SVH50 handler: python options: show_root_heading: false heading_level: 4 -## M30S VH60 +## M30S VH60 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S.BTMinerM30SVH60 handler: python options: show_root_heading: false heading_level: 4 -## M30S VI20 +## M30S VI20 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S.BTMinerM30SVI20 handler: python options: show_root_heading: false heading_level: 4 -## M30S+ V10 +## M30S+ V10 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus.BTMinerM30SPlusV10 handler: python options: show_root_heading: false heading_level: 4 -## M30S+ V20 +## M30S+ V20 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus.BTMinerM30SPlusV20 handler: python options: show_root_heading: false heading_level: 4 -## M30S+ V30 +## M30S+ V30 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus.BTMinerM30SPlusV30 handler: python options: show_root_heading: false heading_level: 4 -## M30S+ V40 +## M30S+ V40 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus.BTMinerM30SPlusV40 handler: python options: show_root_heading: false heading_level: 4 -## M30S+ V50 +## M30S+ V50 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus.BTMinerM30SPlusV50 handler: python options: show_root_heading: false heading_level: 4 -## M30S+ V60 +## M30S+ V60 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus.BTMinerM30SPlusV60 handler: python options: show_root_heading: false heading_level: 4 -## M30S+ V70 +## M30S+ V70 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus.BTMinerM30SPlusV70 handler: python options: show_root_heading: false heading_level: 4 -## M30S+ V80 +## M30S+ V80 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus.BTMinerM30SPlusV80 handler: python options: show_root_heading: false heading_level: 4 -## M30S+ V90 +## M30S+ V90 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus.BTMinerM30SPlusV90 handler: python options: show_root_heading: false heading_level: 4 -## M30S+ V100 +## M30S+ V100 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus.BTMinerM30SPlusV100 handler: python options: show_root_heading: false heading_level: 4 -## M30S+ VE30 +## M30S+ VE30 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus.BTMinerM30SPlusVE30 handler: python options: show_root_heading: false heading_level: 4 -## M30S+ VE40 +## M30S+ VE40 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus.BTMinerM30SPlusVE40 handler: python options: show_root_heading: false heading_level: 4 -## M30S+ VE50 +## M30S+ VE50 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus.BTMinerM30SPlusVE50 handler: python options: show_root_heading: false heading_level: 4 -## M30S+ VE60 +## M30S+ VE60 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus.BTMinerM30SPlusVE60 handler: python options: show_root_heading: false heading_level: 4 -## M30S+ VE70 +## M30S+ VE70 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus.BTMinerM30SPlusVE70 handler: python options: show_root_heading: false heading_level: 4 -## M30S+ VE80 +## M30S+ VE80 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus.BTMinerM30SPlusVE80 handler: python options: show_root_heading: false heading_level: 4 -## M30S+ VE90 +## M30S+ VE90 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus.BTMinerM30SPlusVE90 handler: python options: show_root_heading: false heading_level: 4 -## M30S+ VE100 +## M30S+ VE100 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus.BTMinerM30SPlusVE100 handler: python options: show_root_heading: false heading_level: 4 -## M30S+ VF20 +## M30S+ VF20 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus.BTMinerM30SPlusVF20 handler: python options: show_root_heading: false heading_level: 4 -## M30S+ VF30 +## M30S+ VF30 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus.BTMinerM30SPlusVF30 handler: python options: show_root_heading: false heading_level: 4 -## M30S+ VG20 +## M30S+ VG20 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus.BTMinerM30SPlusVG20 handler: python options: show_root_heading: false heading_level: 4 -## M30S+ VG30 +## M30S+ VG30 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus.BTMinerM30SPlusVG30 handler: python options: show_root_heading: false heading_level: 4 -## M30S+ VG40 +## M30S+ VG40 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus.BTMinerM30SPlusVG40 handler: python options: show_root_heading: false heading_level: 4 -## M30S+ VG50 +## M30S+ VG50 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus.BTMinerM30SPlusVG50 handler: python options: show_root_heading: false heading_level: 4 -## M30S+ VG60 +## M30S+ VG60 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus.BTMinerM30SPlusVG60 handler: python options: show_root_heading: false heading_level: 4 -## M30S+ VH10 +## M30S+ VH10 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus.BTMinerM30SPlusVH10 handler: python options: show_root_heading: false heading_level: 4 -## M30S+ VH20 +## M30S+ VH20 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus.BTMinerM30SPlusVH20 handler: python options: show_root_heading: false heading_level: 4 -## M30S+ VH30 +## M30S+ VH30 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus.BTMinerM30SPlusVH30 handler: python options: show_root_heading: false heading_level: 4 -## M30S+ VH40 +## M30S+ VH40 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus.BTMinerM30SPlusVH40 handler: python options: show_root_heading: false heading_level: 4 -## M30S+ VH50 +## M30S+ VH50 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus.BTMinerM30SPlusVH50 handler: python options: show_root_heading: false heading_level: 4 -## M30S+ VH60 +## M30S+ VH60 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus.BTMinerM30SPlusVH60 handler: python options: show_root_heading: false heading_level: 4 -## M30S++ V10 +## M30S++ V10 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus_Plus.BTMinerM30SPlusPlusV10 handler: python options: show_root_heading: false heading_level: 4 -## M30S++ V20 +## M30S++ V20 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus_Plus.BTMinerM30SPlusPlusV20 handler: python options: show_root_heading: false heading_level: 4 -## M30S++ VE30 +## M30S++ VE30 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus_Plus.BTMinerM30SPlusPlusVE30 handler: python options: show_root_heading: false heading_level: 4 -## M30S++ VE40 +## M30S++ VE40 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus_Plus.BTMinerM30SPlusPlusVE40 handler: python options: show_root_heading: false heading_level: 4 -## M30S++ VE50 +## M30S++ VE50 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus_Plus.BTMinerM30SPlusPlusVE50 handler: python options: show_root_heading: false heading_level: 4 -## M30S++ VF40 +## M30S++ VF40 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus_Plus.BTMinerM30SPlusPlusVF40 handler: python options: show_root_heading: false heading_level: 4 -## M30S++ VG30 +## M30S++ VG30 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus_Plus.BTMinerM30SPlusPlusVG30 handler: python options: show_root_heading: false heading_level: 4 -## M30S++ VG40 +## M30S++ VG40 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus_Plus.BTMinerM30SPlusPlusVG40 handler: python options: show_root_heading: false heading_level: 4 -## M30S++ VG50 +## M30S++ VG50 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus_Plus.BTMinerM30SPlusPlusVG50 handler: python options: show_root_heading: false heading_level: 4 -## M30S++ VH10 +## M30S++ VH10 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus_Plus.BTMinerM30SPlusPlusVH10 handler: python options: show_root_heading: false heading_level: 4 -## M30S++ VH20 +## M30S++ VH20 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus_Plus.BTMinerM30SPlusPlusVH20 handler: python options: show_root_heading: false heading_level: 4 -## M30S++ VH30 +## M30S++ VH30 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus_Plus.BTMinerM30SPlusPlusVH30 handler: python options: show_root_heading: false heading_level: 4 -## M30S++ VH40 +## M30S++ VH40 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus_Plus.BTMinerM30SPlusPlusVH40 handler: python options: show_root_heading: false heading_level: 4 -## M30S++ VH50 +## M30S++ VH50 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus_Plus.BTMinerM30SPlusPlusVH50 handler: python options: show_root_heading: false heading_level: 4 -## M30S++ VH60 +## M30S++ VH60 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus_Plus.BTMinerM30SPlusPlusVH60 handler: python options: show_root_heading: false heading_level: 4 -## M30S++ VH70 +## M30S++ VH70 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus_Plus.BTMinerM30SPlusPlusVH70 handler: python options: show_root_heading: false heading_level: 4 -## M30S++ VH80 +## M30S++ VH80 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus_Plus.BTMinerM30SPlusPlusVH80 handler: python options: show_root_heading: false heading_level: 4 -## M30S++ VH90 +## M30S++ VH90 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus_Plus.BTMinerM30SPlusPlusVH90 handler: python options: show_root_heading: false heading_level: 4 -## M30S++ VH100 +## M30S++ VH100 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus_Plus.BTMinerM30SPlusPlusVH100 handler: python options: show_root_heading: false heading_level: 4 -## M30S++ VJ20 +## M30S++ VJ20 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus_Plus.BTMinerM30SPlusPlusVJ20 handler: python options: show_root_heading: false heading_level: 4 -## M30S++ VJ30 +## M30S++ VJ30 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus_Plus.BTMinerM30SPlusPlusVJ30 handler: python options: show_root_heading: false heading_level: 4 -## M31 V10 +## M31 V10 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M31.BTMinerM31V10 handler: python options: show_root_heading: false heading_level: 4 -## M31 V20 +## M31 V20 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M31.BTMinerM31V20 handler: python options: show_root_heading: false heading_level: 4 -## M31H V10 +## M31H V10 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M31H.BTMinerM31HV10 handler: python options: show_root_heading: false heading_level: 4 -## M31H V40 +## M31H V40 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M31H.BTMinerM31HV40 handler: python options: show_root_heading: false heading_level: 4 -## M30L V10 +## M30L V10 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M31L.BTMinerM31LV10 handler: python options: show_root_heading: false heading_level: 4 -## M31S V10 +## M31S V10 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M31S.BTMinerM31SV10 handler: python options: show_root_heading: false heading_level: 4 -## M31S V20 +## M31S V20 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M31S.BTMinerM31SV20 handler: python options: show_root_heading: false heading_level: 4 -## M31S V30 +## M31S V30 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M31S.BTMinerM31SV30 handler: python options: show_root_heading: false heading_level: 4 -## M31S V40 +## M31S V40 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M31S.BTMinerM31SV40 handler: python options: show_root_heading: false heading_level: 4 -## M31S V50 +## M31S V50 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M31S.BTMinerM31SV50 handler: python options: show_root_heading: false heading_level: 4 -## M31S V60 +## M31S V60 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M31S.BTMinerM31SV60 handler: python options: show_root_heading: false heading_level: 4 -## M31S V70 +## M31S V70 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M31S.BTMinerM31SV70 handler: python options: show_root_heading: false heading_level: 4 -## M31S V80 +## M31S V80 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M31S.BTMinerM31SV80 handler: python options: show_root_heading: false heading_level: 4 -## M31S V90 +## M31S V90 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M31S.BTMinerM31SV90 handler: python options: show_root_heading: false heading_level: 4 -## M31S VE10 +## M31S VE10 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M31S.BTMinerM31SVE10 handler: python options: show_root_heading: false heading_level: 4 -## M31S VE20 +## M31S VE20 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M31S.BTMinerM31SVE20 handler: python options: show_root_heading: false heading_level: 4 -## M31S VE30 +## M31S VE30 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M31S.BTMinerM31SVE30 handler: python options: show_root_heading: false heading_level: 4 -## M31SE V10 +## M31SE V10 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M31SE.BTMinerM31SEV10 handler: python options: show_root_heading: false heading_level: 4 -## M31SE V20 +## M31SE V20 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M31SE.BTMinerM31SEV20 handler: python options: show_root_heading: false heading_level: 4 -## M31SE V30 +## M31SE V30 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M31SE.BTMinerM31SEV30 handler: python options: show_root_heading: false heading_level: 4 -## M31S+ V10 +## M31S+ V10 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M31S_Plus.BTMinerM31SPlusV10 handler: python options: show_root_heading: false heading_level: 4 -## M31S+ V20 +## M31S+ V20 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M31S_Plus.BTMinerM31SPlusV20 handler: python options: show_root_heading: false heading_level: 4 -## M31S+ V30 +## M31S+ V30 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M31S_Plus.BTMinerM31SPlusV30 handler: python options: show_root_heading: false heading_level: 4 -## M31S+ V40 +## M31S+ V40 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M31S_Plus.BTMinerM31SPlusV40 handler: python options: show_root_heading: false heading_level: 4 -## M31S+ V50 +## M31S+ V50 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M31S_Plus.BTMinerM31SPlusV50 handler: python options: show_root_heading: false heading_level: 4 -## M31S+ V60 +## M31S+ V60 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M31S_Plus.BTMinerM31SPlusV60 handler: python options: show_root_heading: false heading_level: 4 -## M31S+ V80 +## M31S+ V80 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M31S_Plus.BTMinerM31SPlusV80 handler: python options: show_root_heading: false heading_level: 4 -## M31S+ V90 +## M31S+ V90 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M31S_Plus.BTMinerM31SPlusV90 handler: python options: show_root_heading: false heading_level: 4 -## M31S+ V100 +## M31S+ V100 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M31S_Plus.BTMinerM31SPlusV100 handler: python options: show_root_heading: false heading_level: 4 -## M31S+ VE10 +## M31S+ VE10 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M31S_Plus.BTMinerM31SPlusVE10 handler: python options: show_root_heading: false heading_level: 4 -## M31S+ VE20 +## M31S+ VE20 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M31S_Plus.BTMinerM31SPlusVE20 handler: python options: show_root_heading: false heading_level: 4 -## M31S+ VE30 +## M31S+ VE30 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M31S_Plus.BTMinerM31SPlusVE30 handler: python options: show_root_heading: false heading_level: 4 -## M31S+ VE40 +## M31S+ VE40 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M31S_Plus.BTMinerM31SPlusVE40 handler: python options: show_root_heading: false heading_level: 4 -## M31S+ VE50 +## M31S+ VE50 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M31S_Plus.BTMinerM31SPlusVE50 handler: python options: show_root_heading: false heading_level: 4 -## M31S+ VE60 +## M31S+ VE60 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M31S_Plus.BTMinerM31SPlusVE60 handler: python options: show_root_heading: false heading_level: 4 -## M31S+ VE80 +## M31S+ VE80 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M31S_Plus.BTMinerM31SPlusVE80 handler: python options: show_root_heading: false heading_level: 4 -## M31S+ VF20 +## M31S+ VF20 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M31S_Plus.BTMinerM31SPlusVF20 handler: python options: show_root_heading: false heading_level: 4 -## M31S+ VF30 +## M31S+ VF30 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M31S_Plus.BTMinerM31SPlusVF30 handler: python options: show_root_heading: false heading_level: 4 -## M31S+ VG20 +## M31S+ VG20 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M31S_Plus.BTMinerM31SPlusVG20 handler: python options: show_root_heading: false heading_level: 4 -## M31S+ VG30 +## M31S+ VG30 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M31S_Plus.BTMinerM31SPlusVG30 handler: python options: show_root_heading: false heading_level: 4 -## M32 V10 +## M32 V10 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M32.BTMinerM32V10 handler: python options: show_root_heading: false heading_level: 4 -## M32 V20 +## M32 V20 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M32.BTMinerM32V20 handler: python options: show_root_heading: false heading_level: 4 -## M33 V10 +## M33 V10 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M33.BTMinerM33V10 handler: python options: show_root_heading: false heading_level: 4 -## M33 V20 +## M33 V20 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M33.BTMinerM33V20 handler: python options: show_root_heading: false heading_level: 4 -## M33 V30 +## M33 V30 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M33.BTMinerM33V30 handler: python options: show_root_heading: false heading_level: 4 -## M33S VG30 +## M33S VG30 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M33S.BTMinerM33SVG30 handler: python options: show_root_heading: false heading_level: 4 -## M33S+ VG20 +## M33S+ VG20 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M33S_Plus.BTMinerM33SPlusVG20 handler: python options: show_root_heading: false heading_level: 4 -## M33S+ VH20 +## M33S+ VH20 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M33S_Plus.BTMinerM33SPlusVH20 handler: python options: show_root_heading: false heading_level: 4 -## M33S+ VH30 +## M33S+ VH30 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M33S_Plus.BTMinerM33SPlusVH30 handler: python options: show_root_heading: false heading_level: 4 -## M33S++ VH20 +## M33S++ VH20 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M33S_Plus_Plus.BTMinerM33SPlusPlusVH20 handler: python options: show_root_heading: false heading_level: 4 -## M33S++ VH30 +## M33S++ VH30 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M33S_Plus_Plus.BTMinerM33SPlusPlusVH30 handler: python options: show_root_heading: false heading_level: 4 -## M33S++ VG40 +## M33S++ VG40 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M33S_Plus_Plus.BTMinerM33SPlusPlusVG40 handler: python options: show_root_heading: false heading_level: 4 -## M34S+ VE10 +## M34S+ VE10 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M34S_Plus.BTMinerM34SPlusVE10 handler: python options: show_root_heading: false heading_level: 4 -## M36S VE10 +## M36S VE10 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M36S.BTMinerM36SVE10 handler: python options: show_root_heading: false heading_level: 4 -## M36S+ VG30 +## M36S+ VG30 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M36S_Plus.BTMinerM36SPlusVG30 handler: python options: show_root_heading: false heading_level: 4 -## M36S++ VH30 +## M36S++ VH30 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M36S_Plus_Plus.BTMinerM36SPlusPlusVH30 handler: python options: show_root_heading: false heading_level: 4 -## M39 V10 +## M39 V10 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M39.BTMinerM39V10 handler: python options: show_root_heading: false heading_level: 4 -## M39 V20 +## M39 V20 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M39.BTMinerM39V20 handler: python options: show_root_heading: false heading_level: 4 -## M39 V30 +## M39 V30 (Stock) ::: pyasic.miners.whatsminer.btminer.M3X.M39.BTMinerM39V30 handler: python options: diff --git a/docs/miners/whatsminer/M5X.md b/docs/miners/whatsminer/M5X.md index 2ef24281..34249629 100644 --- a/docs/miners/whatsminer/M5X.md +++ b/docs/miners/whatsminer/M5X.md @@ -1,259 +1,259 @@ # pyasic ## M5X Models -## M50 VE30 +## M50 VE30 (Stock) ::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VE30 handler: python options: show_root_heading: false heading_level: 4 -## M50 VG30 +## M50 VG30 (Stock) ::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VG30 handler: python options: show_root_heading: false heading_level: 4 -## M50 VH10 +## M50 VH10 (Stock) ::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH10 handler: python options: show_root_heading: false heading_level: 4 -## M50 VH20 +## M50 VH20 (Stock) ::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH20 handler: python options: show_root_heading: false heading_level: 4 -## M50 VH30 +## M50 VH30 (Stock) ::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH30 handler: python options: show_root_heading: false heading_level: 4 -## M50 VH40 +## M50 VH40 (Stock) ::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH40 handler: python options: show_root_heading: false heading_level: 4 -## M50 VH50 +## M50 VH50 (Stock) ::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH50 handler: python options: show_root_heading: false heading_level: 4 -## M50 VH60 +## M50 VH60 (Stock) ::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH60 handler: python options: show_root_heading: false heading_level: 4 -## M50 VH70 +## M50 VH70 (Stock) ::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH70 handler: python options: show_root_heading: false heading_level: 4 -## M50 VH80 +## M50 VH80 (Stock) ::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH80 handler: python options: show_root_heading: false heading_level: 4 -## M50 VJ10 +## M50 VJ10 (Stock) ::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VJ10 handler: python options: show_root_heading: false heading_level: 4 -## M50 VJ20 +## M50 VJ20 (Stock) ::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VJ20 handler: python options: show_root_heading: false heading_level: 4 -## M50 VJ30 +## M50 VJ30 (Stock) ::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VJ30 handler: python options: show_root_heading: false heading_level: 4 -## M50S VJ10 +## M50S VJ10 (Stock) ::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVJ10 handler: python options: show_root_heading: false heading_level: 4 -## M50S VJ20 +## M50S VJ20 (Stock) ::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVJ20 handler: python options: show_root_heading: false heading_level: 4 -## M50S VJ30 +## M50S VJ30 (Stock) ::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVJ30 handler: python options: show_root_heading: false heading_level: 4 -## M50S VH10 +## M50S VH10 (Stock) ::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVH10 handler: python options: show_root_heading: false heading_level: 4 -## M50S VH20 +## M50S VH20 (Stock) ::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVH20 handler: python options: show_root_heading: false heading_level: 4 -## M50S VH30 +## M50S VH30 (Stock) ::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVH30 handler: python options: show_root_heading: false heading_level: 4 -## M50S VH40 +## M50S VH40 (Stock) ::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVH40 handler: python options: show_root_heading: false heading_level: 4 -## M50S VH50 +## M50S VH50 (Stock) ::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVH50 handler: python options: show_root_heading: false heading_level: 4 -## M50S+ VH30 +## M50S+ VH30 (Stock) ::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus.BTMinerM50SPlusVH30 handler: python options: show_root_heading: false heading_level: 4 -## M50S+ VH40 +## M50S+ VH40 (Stock) ::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus.BTMinerM50SPlusVH40 handler: python options: show_root_heading: false heading_level: 4 -## M50S+ VJ30 +## M50S+ VJ30 (Stock) ::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus.BTMinerM50SPlusVJ30 handler: python options: show_root_heading: false heading_level: 4 -## M50S+ VK20 +## M50S+ VK20 (Stock) ::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus.BTMinerM50SPlusVK20 handler: python options: show_root_heading: false heading_level: 4 -## M50S++ VK10 +## M50S++ VK10 (Stock) ::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus_Plus.BTMinerM50SPlusPlusVK10 handler: python options: show_root_heading: false heading_level: 4 -## M50S++ VK20 +## M50S++ VK20 (Stock) ::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus_Plus.BTMinerM50SPlusPlusVK20 handler: python options: show_root_heading: false heading_level: 4 -## M50S++ VK30 +## M50S++ VK30 (Stock) ::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus_Plus.BTMinerM50SPlusPlusVK30 handler: python options: show_root_heading: false heading_level: 4 -## M53 VH30 +## M53 VH30 (Stock) ::: pyasic.miners.whatsminer.btminer.M5X.M53.BTMinerM53VH30 handler: python options: show_root_heading: false heading_level: 4 -## M53S VH30 +## M53S VH30 (Stock) ::: pyasic.miners.whatsminer.btminer.M5X.M53S.BTMinerM53SVH30 handler: python options: show_root_heading: false heading_level: 4 -## M53S VJ40 +## M53S VJ40 (Stock) ::: pyasic.miners.whatsminer.btminer.M5X.M53S.BTMinerM53SVJ40 handler: python options: show_root_heading: false heading_level: 4 -## M53S+ VJ30 +## M53S+ VJ30 (Stock) ::: pyasic.miners.whatsminer.btminer.M5X.M53S_Plus.BTMinerM53SPlusVJ30 handler: python options: show_root_heading: false heading_level: 4 -## M53S++ VK10 +## M53S++ VK10 (Stock) ::: pyasic.miners.whatsminer.btminer.M5X.M53S_Plus_Plus.BTMinerM53SPlusPlusVK10 handler: python options: show_root_heading: false heading_level: 4 -## M56 VH30 +## M56 VH30 (Stock) ::: pyasic.miners.whatsminer.btminer.M5X.M56.BTMinerM56VH30 handler: python options: show_root_heading: false heading_level: 4 -## M56S VH30 +## M56S VH30 (Stock) ::: pyasic.miners.whatsminer.btminer.M5X.M56S.BTMinerM56SVH30 handler: python options: show_root_heading: false heading_level: 4 -## M56S+ VJ30 +## M56S+ VJ30 (Stock) ::: pyasic.miners.whatsminer.btminer.M5X.M56S_Plus.BTMinerM56SPlusVJ30 handler: python options: show_root_heading: false heading_level: 4 -## M59 VH30 +## M59 VH30 (Stock) ::: pyasic.miners.whatsminer.btminer.M5X.M59.BTMinerM59VH30 handler: python options: diff --git a/docs/miners/whatsminer/M6X.md b/docs/miners/whatsminer/M6X.md index bf67327d..be87c25b 100644 --- a/docs/miners/whatsminer/M6X.md +++ b/docs/miners/whatsminer/M6X.md @@ -1,133 +1,133 @@ # pyasic ## M6X Models -## M60 VK10 +## M60 VK10 (Stock) ::: pyasic.miners.whatsminer.btminer.M6X.M60.BTMinerM60VK10 handler: python options: show_root_heading: false heading_level: 4 -## M60 VK20 +## M60 VK20 (Stock) ::: pyasic.miners.whatsminer.btminer.M6X.M60.BTMinerM60VK20 handler: python options: show_root_heading: false heading_level: 4 -## M60 VK30 +## M60 VK30 (Stock) ::: pyasic.miners.whatsminer.btminer.M6X.M60.BTMinerM60VK30 handler: python options: show_root_heading: false heading_level: 4 -## M60 VK40 +## M60 VK40 (Stock) ::: pyasic.miners.whatsminer.btminer.M6X.M60.BTMinerM60VK40 handler: python options: show_root_heading: false heading_level: 4 -## M60S VK10 +## M60S VK10 (Stock) ::: pyasic.miners.whatsminer.btminer.M6X.M60S.BTMinerM60SVK10 handler: python options: show_root_heading: false heading_level: 4 -## M60S VK20 +## M60S VK20 (Stock) ::: pyasic.miners.whatsminer.btminer.M6X.M60S.BTMinerM60SVK20 handler: python options: show_root_heading: false heading_level: 4 -## M60S VK30 +## M60S VK30 (Stock) ::: pyasic.miners.whatsminer.btminer.M6X.M60S.BTMinerM60SVK30 handler: python options: show_root_heading: false heading_level: 4 -## M60S VK40 +## M60S VK40 (Stock) ::: pyasic.miners.whatsminer.btminer.M6X.M60S.BTMinerM60SVK40 handler: python options: show_root_heading: false heading_level: 4 -## M63 VK10 +## M63 VK10 (Stock) ::: pyasic.miners.whatsminer.btminer.M6X.M63.BTMinerM63VK10 handler: python options: show_root_heading: false heading_level: 4 -## M63 VK20 +## M63 VK20 (Stock) ::: pyasic.miners.whatsminer.btminer.M6X.M63.BTMinerM63VK20 handler: python options: show_root_heading: false heading_level: 4 -## M63 VK30 +## M63 VK30 (Stock) ::: pyasic.miners.whatsminer.btminer.M6X.M63.BTMinerM63VK30 handler: python options: show_root_heading: false heading_level: 4 -## M63S VK10 +## M63S VK10 (Stock) ::: pyasic.miners.whatsminer.btminer.M6X.M63S.BTMinerM63SVK10 handler: python options: show_root_heading: false heading_level: 4 -## M63S VK20 +## M63S VK20 (Stock) ::: pyasic.miners.whatsminer.btminer.M6X.M63S.BTMinerM63SVK20 handler: python options: show_root_heading: false heading_level: 4 -## M63S VK30 +## M63S VK30 (Stock) ::: pyasic.miners.whatsminer.btminer.M6X.M63S.BTMinerM63SVK30 handler: python options: show_root_heading: false heading_level: 4 -## M66 VK20 +## M66 VK20 (Stock) ::: pyasic.miners.whatsminer.btminer.M6X.M66.BTMinerM66VK20 handler: python options: show_root_heading: false heading_level: 4 -## M66 VK30 +## M66 VK30 (Stock) ::: pyasic.miners.whatsminer.btminer.M6X.M66.BTMinerM66VK30 handler: python options: show_root_heading: false heading_level: 4 -## M66S VK20 +## M66S VK20 (Stock) ::: pyasic.miners.whatsminer.btminer.M6X.M66S.BTMinerM66SVK20 handler: python options: show_root_heading: false heading_level: 4 -## M66S VK30 +## M66S VK30 (Stock) ::: pyasic.miners.whatsminer.btminer.M6X.M66S.BTMinerM66SVK30 handler: python options: show_root_heading: false heading_level: 4 -## M66S VK40 +## M66S VK40 (Stock) ::: pyasic.miners.whatsminer.btminer.M6X.M66S.BTMinerM66SVK40 handler: python options: diff --git a/docs/requirements.txt b/docs/requirements.txt index 55112534..29721bb6 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,3 +1,4 @@ jinja2<3.1.4 mkdocs mkdocstrings[python] +zipp>=3.19.1 # not directly required, pinned by Snyk to avoid a vulnerability diff --git a/mkdocs.yml b/mkdocs.yml index 0e99b1b6..7ed5fb21 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -68,6 +68,8 @@ nav: - Auradine AD: "miners/auradine/AD.md" - Auradine AI: "miners/auradine/AI.md" - Auradine AT: "miners/auradine/AT.md" + - Blockminer: "miners/blockminer/blockminer.md" + - BitAxe BM: "miners/bitaxe/BM.md" - Base Miner: "miners/base_miner.md" - Settings: - Settings: "settings/settings.md" diff --git a/pyasic/config/__init__.py b/pyasic/config/__init__.py index 4b1af0e9..bacf5c38 100644 --- a/pyasic/config/__init__.py +++ b/pyasic/config/__init__.py @@ -140,6 +140,14 @@ class MinerConfig: **self.pools.as_mara(user_suffix=user_suffix), } + def as_bitaxe(self, user_suffix: str = None) -> dict: + return { + **self.fan_mode.as_bitaxe(), + **self.temperature.as_bitaxe(), + **self.mining_mode.as_bitaxe(), + **self.pools.as_bitaxe(user_suffix=user_suffix), + } + @classmethod def from_dict(cls, dict_conf: dict) -> "MinerConfig": """Constructs a MinerConfig object from a dictionary.""" @@ -235,3 +243,10 @@ class MinerConfig: fan_mode=FanModeConfig.from_mara(web_miner_config), mining_mode=MiningModeConfig.from_mara(web_miner_config), ) + + @classmethod + def from_bitaxe(cls, web_system_info: dict) -> "MinerConfig": + return cls( + pools=PoolConfig.from_bitaxe(web_system_info), + fan_mode=FanModeConfig.from_bitaxe(web_system_info), + ) diff --git a/pyasic/config/base.py b/pyasic/config/base.py index 08834068..c8e55f00 100644 --- a/pyasic/config/base.py +++ b/pyasic/config/base.py @@ -60,6 +60,9 @@ class MinerConfigOption(Enum): def as_mara(self) -> dict: return self.value.as_mara() + def as_bitaxe(self) -> dict: + return self.value.as_bitaxe() + def __call__(self, *args, **kwargs): return self.value(*args, **kwargs) @@ -119,6 +122,9 @@ class MinerConfigValue: def as_mara(self) -> dict: return {} + def as_bitaxe(self) -> dict: + return {} + def __getitem__(self, item): try: return getattr(self, item) diff --git a/pyasic/config/fans.py b/pyasic/config/fans.py index ed0ef002..6359b2fd 100644 --- a/pyasic/config/fans.py +++ b/pyasic/config/fans.py @@ -80,6 +80,9 @@ class FanModeNormal(MinerConfigValue): }, } + def as_bitaxe(self) -> dict: + return {"autoFanspeed": 1} + @dataclass class FanModeManual(MinerConfigValue): @@ -138,6 +141,9 @@ class FanModeManual(MinerConfigValue): }, } + def as_bitaxe(self) -> dict: + return {"autoFanspeed": 0, "fanspeed": self.speed} + @dataclass class FanModeImmersion(MinerConfigValue): @@ -291,3 +297,10 @@ class FanModeConfig(MinerConfigOption): except LookupError: pass return cls.default() + + @classmethod + def from_bitaxe(cls, web_system_info: dict): + if web_system_info["autofanspeed"] == 1: + return cls.normal() + else: + return cls.manual(speed=web_system_info["fanspeed"]) diff --git a/pyasic/config/mining/algo.py b/pyasic/config/mining/algo.py index c8c00e79..96021b8f 100644 --- a/pyasic/config/mining/algo.py +++ b/pyasic/config/mining/algo.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from dataclasses import dataclass, field from pyasic.config.base import MinerConfigOption, MinerConfigValue diff --git a/pyasic/config/pools.py b/pyasic/config/pools.py index 19c88262..e2572cd9 100644 --- a/pyasic/config/pools.py +++ b/pyasic/config/pools.py @@ -127,6 +127,13 @@ class Pool(MinerConfigValue): } return {"url": self.url, "user": self.user, "pass": self.password} + def as_bitaxe(self, user_suffix: str = None) -> dict: + return { + "stratumURL": self.url, + "stratumUser": f"{self.user}{user_suffix}", + "stratumPassword": self.password, + } + @classmethod def from_dict(cls, dict_conf: dict | None) -> "Pool": return cls( @@ -194,6 +201,15 @@ class Pool(MinerConfigValue): password=web_pool["pass"], ) + @classmethod + def from_bitaxe(cls, web_system_info: dict) -> "Pool": + url = f"stratum+tcp://{web_system_info['stratumURL']}:{web_system_info['stratumPort']}" + return cls( + url=url, + user=web_system_info["stratumUser"], + password=web_system_info.get("stratumPassword", ""), + ) + @dataclass class PoolGroup(MinerConfigValue): @@ -287,6 +303,9 @@ class PoolGroup(MinerConfigValue): def as_mara(self, user_suffix: str = None) -> list: return [p.as_mara(user_suffix=user_suffix) for p in self.pools] + def as_bitaxe(self, user_suffix: str = None) -> dict: + return self.pools[0].as_bitaxe(user_suffix=user_suffix) + @classmethod def from_dict(cls, dict_conf: dict | None) -> "PoolGroup": cls_conf = {} @@ -360,6 +379,10 @@ class PoolGroup(MinerConfigValue): def from_mara(cls, web_config_pools: dict) -> "PoolGroup": return cls(pools=[Pool.from_mara(pool_conf) for pool_conf in web_config_pools]) + @classmethod + def from_bitaxe(cls, web_system_info: dict) -> "PoolGroup": + return cls(pools=[Pool.from_bitaxe(web_system_info)]) + @dataclass class PoolConfig(MinerConfigValue): @@ -456,6 +479,9 @@ class PoolConfig(MinerConfigValue): return {"pools": self.groups[0].as_mara(user_suffix=user_suffix)} return {"pools": []} + def as_bitaxe(self, user_suffix: str = None) -> dict: + return self.groups[0].as_bitaxe(user_suffix=user_suffix) + @classmethod def from_api(cls, api_pools: dict) -> "PoolConfig": try: @@ -514,3 +540,7 @@ class PoolConfig(MinerConfigValue): @classmethod def from_mara(cls, web_config: dict) -> "PoolConfig": return cls(groups=[PoolGroup.from_mara(web_config["pools"])]) + + @classmethod + def from_bitaxe(cls, web_system_info: dict) -> "PoolConfig": + return cls(groups=[PoolGroup.from_bitaxe(web_system_info)]) diff --git a/pyasic/data/pools.py b/pyasic/data/pools.py index 4ff4e158..f4970fbf 100644 --- a/pyasic/data/pools.py +++ b/pyasic/data/pools.py @@ -1,4 +1,35 @@ from dataclasses import dataclass, field +from enum import Enum +from typing import Optional +from urllib.parse import urlparse + + +class Scheme(Enum): + STRATUM_V1 = "stratum+tcp" + STRATUM_V2 = "stratum2+tcp" + + +@dataclass +class PoolUrl: + scheme: Scheme + host: str + port: int + pubkey: Optional[str] = None + + def __str__(self) -> str: + if self.scheme == Scheme.STRATUM_V2 and self.pubkey: + return f"{self.scheme.value}://{self.host}:{self.port}/{self.pubkey}" + else: + return f"{self.scheme.value}://{self.host}:{self.port}" + + @classmethod + def from_str(cls, url: str) -> "PoolUrl": + parsed_url = urlparse(url) + scheme = Scheme(parsed_url.scheme) + host = parsed_url.hostname + port = parsed_url.port + pubkey = parsed_url.path.lstrip("/") if scheme == Scheme.STRATUM_V2 else None + return cls(scheme=scheme, host=host, port=port, pubkey=pubkey) @dataclass @@ -19,13 +50,13 @@ class PoolMetrics: pool_stale_percent: Percentage of stale shares by the pool. """ + url: PoolUrl accepted: int = None rejected: int = None get_failures: int = None remote_failures: int = None active: bool = None alive: bool = None - url: str = None index: int = None user: str = None pool_rejected_percent: float = field(init=False) diff --git a/pyasic/device/makes.py b/pyasic/device/makes.py index f31bfdcd..cfb1ecbe 100644 --- a/pyasic/device/makes.py +++ b/pyasic/device/makes.py @@ -25,6 +25,7 @@ class MinerMake(str, Enum): GOLDSHELL = "Goldshell" AURADINE = "Auradine" EPIC = "ePIC" + BITAXE = "BitAxe" def __str__(self): return self.value diff --git a/pyasic/device/models.py b/pyasic/device/models.py index 883da95c..8eab6655 100644 --- a/pyasic/device/models.py +++ b/pyasic/device/models.py @@ -329,6 +329,15 @@ class AuradineModels(str, Enum): return self.value +class BitAxeModels(str, Enum): + BM1366 = "Ultra" + BM1368 = "Supra" + BM1397 = "Max" + + def __str__(self): + return self.value + + class MinerModel: ANTMINER = AntminerModels WHATSMINER = WhatsminerModels @@ -337,3 +346,4 @@ class MinerModel: GOLDSHELL = GoldshellModels AURADINE = AuradineModels EPIC = ePICModels + BITAXE = BitAxeModels diff --git a/pyasic/miners/antminer/vnish/X19/S19.py b/pyasic/miners/antminer/vnish/X19/S19.py index 032d5db9..7dd9dd11 100644 --- a/pyasic/miners/antminer/vnish/X19/S19.py +++ b/pyasic/miners/antminer/vnish/X19/S19.py @@ -24,6 +24,7 @@ from pyasic.miners.device.models import ( S19jPro, S19NoPIC, S19Pro, + S19ProHydro, ) @@ -57,3 +58,7 @@ class VNishS19j(VNish, S19j): class VNishS19jPro(VNish, S19jPro): pass + + +class VNishS19ProHydro(VNish, S19ProHydro): + pass diff --git a/pyasic/miners/antminer/vnish/X19/__init__.py b/pyasic/miners/antminer/vnish/X19/__init__.py index f69c45e2..b7f679c0 100644 --- a/pyasic/miners/antminer/vnish/X19/__init__.py +++ b/pyasic/miners/antminer/vnish/X19/__init__.py @@ -22,6 +22,7 @@ from .S19 import ( VNishS19jPro, VNishS19NoPIC, VNishS19Pro, + VNishS19ProHydro, VNishS19XP, ) from .T19 import VNishT19 diff --git a/pyasic/miners/backends/antminer.py b/pyasic/miners/backends/antminer.py index 26b803c4..5d162730 100644 --- a/pyasic/miners/backends/antminer.py +++ b/pyasic/miners/backends/antminer.py @@ -19,6 +19,8 @@ from typing import List, Optional, Union from pyasic.config import MinerConfig, MiningModeConfig from pyasic.data import AlgoHashRate, Fan, HashBoard, HashUnit from pyasic.data.error_codes import MinerErrorData, X19Error +from pyasic.data.pools import PoolMetrics, PoolUrl +from pyasic.errors import APIError from pyasic.miners.backends.bmminer import BMMiner from pyasic.miners.backends.cgminer import CGMiner from pyasic.miners.data import ( @@ -31,8 +33,6 @@ from pyasic.miners.data import ( from pyasic.rpc.antminer import AntminerRPCAPI from pyasic.ssh.antminer import AntminerModernSSH from pyasic.web.antminer import AntminerModernWebAPI, AntminerOldWebAPI -from pyasic.data.pools import PoolMetrics -from pyasic.errors import APIError ANTMINER_MODERN_DATA_LOC = DataLocations( **{ @@ -95,7 +95,7 @@ class AntminerModern(BMMiner): web: AntminerModernWebAPI _rpc_cls = AntminerRPCAPI - web: AntminerRPCAPI + rpc: AntminerRPCAPI _ssh_cls = AntminerModernSSH ssh: AntminerModernSSH @@ -156,7 +156,7 @@ class AntminerModern(BMMiner): await self.send_config(cfg) return True - async def _get_hostname(self, web_get_system_info: dict = None) -> Union[str, None]: + async def _get_hostname(self, web_get_system_info: dict = None) -> Optional[str]: if web_get_system_info is None: try: web_get_system_info = await self.web.get_system_info() @@ -169,7 +169,7 @@ class AntminerModern(BMMiner): except KeyError: pass - async def _get_mac(self, web_get_system_info: dict = None) -> Union[str, None]: + async def _get_mac(self, web_get_system_info: dict = None) -> Optional[str]: if web_get_system_info is None: try: web_get_system_info = await self.web.get_system_info() @@ -264,7 +264,9 @@ class AntminerModern(BMMiner): pass return self.light - async def _get_expected_hashrate(self, rpc_stats: dict = None) -> Optional[float]: + async def _get_expected_hashrate( + self, rpc_stats: dict = None + ) -> Optional[AlgoHashRate]: if rpc_stats is None: try: rpc_stats = await self.rpc.stats() @@ -368,6 +370,8 @@ class AntminerModern(BMMiner): try: pools = rpc_pools.get("POOLS", []) for pool_info in pools: + url = pool_info.get("URL") + pool_url = PoolUrl.from_str(url) if url else None pool_data = PoolMetrics( accepted=pool_info.get("Accepted"), rejected=pool_info.get("Rejected"), @@ -375,10 +379,9 @@ class AntminerModern(BMMiner): remote_failures=pool_info.get("Remote Failures"), active=pool_info.get("Stratum Active"), alive=pool_info.get("Status") == "Alive", - url=pool_info.get("URL"), + url=pool_url, user=pool_info.get("User"), - index=pool_info.get("POOL") - + index=pool_info.get("POOL"), ) pools_data.append(pool_data) except LookupError: @@ -446,7 +449,7 @@ class AntminerOld(CGMiner): self.config = config await self.web.set_miner_conf(config.as_am_old(user_suffix=user_suffix)) - async def _get_mac(self) -> Union[str, None]: + async def _get_mac(self) -> Optional[str]: try: data = await self.web.get_system_info() if data: diff --git a/pyasic/miners/backends/auradine.py b/pyasic/miners/backends/auradine.py index 690848d1..893f0770 100644 --- a/pyasic/miners/backends/auradine.py +++ b/pyasic/miners/backends/auradine.py @@ -281,7 +281,7 @@ class Auradine(StockFirmware): except LookupError: pass - async def _get_hashrate(self, rpc_summary: dict = None) -> Optional[float]: + async def _get_hashrate(self, rpc_summary: dict = None) -> Optional[AlgoHashRate]: if rpc_summary is None: try: rpc_summary = await self.rpc.summary() diff --git a/pyasic/miners/backends/avalonminer.py b/pyasic/miners/backends/avalonminer.py index da552e61..a831ce41 100644 --- a/pyasic/miners/backends/avalonminer.py +++ b/pyasic/miners/backends/avalonminer.py @@ -173,7 +173,7 @@ class AvalonMiner(CGMiner): except (KeyError, ValueError): pass - async def _get_hashrate(self, rpc_devs: dict = None) -> Optional[float]: + async def _get_hashrate(self, rpc_devs: dict = None) -> Optional[AlgoHashRate]: if rpc_devs is None: try: rpc_devs = await self.rpc.devs() @@ -238,7 +238,9 @@ class AvalonMiner(CGMiner): return hashboards - async def _get_expected_hashrate(self, rpc_stats: dict = None) -> Optional[float]: + async def _get_expected_hashrate( + self, rpc_stats: dict = None + ) -> Optional[AlgoHashRate]: if rpc_stats is None: try: rpc_stats = await self.rpc.stats() diff --git a/pyasic/miners/backends/bfgminer.py b/pyasic/miners/backends/bfgminer.py index 5b1a3b8c..c3855d57 100644 --- a/pyasic/miners/backends/bfgminer.py +++ b/pyasic/miners/backends/bfgminer.py @@ -105,7 +105,7 @@ class BFGMiner(StockFirmware): return self.fw_ver - async def _get_hashrate(self, rpc_summary: dict = None) -> Optional[float]: + async def _get_hashrate(self, rpc_summary: dict = None) -> Optional[AlgoHashRate]: # get hr from API if rpc_summary is None: try: @@ -207,7 +207,9 @@ class BFGMiner(StockFirmware): return fans - async def _get_expected_hashrate(self, rpc_stats: dict = None) -> Optional[float]: + async def _get_expected_hashrate( + self, rpc_stats: dict = None + ) -> Optional[AlgoHashRate]: # X19 method, not sure compatibility if rpc_stats is None: try: diff --git a/pyasic/miners/backends/bitaxe.py b/pyasic/miners/backends/bitaxe.py new file mode 100644 index 00000000..ca0d7f06 --- /dev/null +++ b/pyasic/miners/backends/bitaxe.py @@ -0,0 +1,189 @@ +from typing import List, Optional + +from pyasic import APIError, MinerConfig +from pyasic.data import AlgoHashRate, Fan, HashBoard, HashUnit +from pyasic.device import MinerFirmware +from pyasic.miners.base import BaseMiner +from pyasic.miners.data import DataFunction, DataLocations, DataOptions, WebAPICommand +from pyasic.web.bitaxe import BitAxeWebAPI + +BITAXE_DATA_LOC = DataLocations( + **{ + str(DataOptions.HASHRATE): DataFunction( + "_get_hashrate", + [WebAPICommand("web_system_info", "system/info")], + ), + str(DataOptions.WATTAGE): DataFunction( + "_get_wattage", + [WebAPICommand("web_system_info", "system/info")], + ), + str(DataOptions.UPTIME): DataFunction( + "_get_uptime", + [WebAPICommand("web_system_info", "system/info")], + ), + str(DataOptions.HASHBOARDS): DataFunction( + "_get_hashboards", + [WebAPICommand("web_system_info", "system/info")], + ), + str(DataOptions.HOSTNAME): DataFunction( + "_get_hostname", + [WebAPICommand("web_system_info", "system/info")], + ), + str(DataOptions.FANS): DataFunction( + "_get_fans", + [WebAPICommand("web_system_info", "system/info")], + ), + str(DataOptions.FW_VERSION): DataFunction( + "_get_fw_ver", + [WebAPICommand("web_system_info", "system/info")], + ), + str(DataOptions.API_VERSION): DataFunction( + "_get_api_ver", + [WebAPICommand("web_system_info", "system/info")], + ), + } +) + + +class BitAxe(BaseMiner): + """Handler for BitAxe""" + + web: BitAxeWebAPI + _web_cls = BitAxeWebAPI + + firmware = MinerFirmware.STOCK + + data_locations = BITAXE_DATA_LOC + + async def reboot(self) -> bool: + await self.web.restart() + return True + + async def get_config(self) -> MinerConfig: + web_system_info = await self.web.system_info() + return MinerConfig.from_bitaxe(web_system_info) + + async def send_config(self, config: MinerConfig, user_suffix: str = None) -> None: + await self.web.update_settings(**config.as_bitaxe()) + + async def _get_wattage(self, web_system_info: dict = None) -> Optional[int]: + if web_system_info is None: + try: + web_system_info = await self.web.system_info() + except APIError: + pass + if web_system_info is not None: + try: + return round(web_system_info["power"]) + except KeyError: + pass + + async def _get_hashrate( + self, web_system_info: dict = None + ) -> Optional[AlgoHashRate]: + if web_system_info is None: + try: + web_system_info = await self.web.system_info() + except APIError: + pass + + if web_system_info is not None: + try: + return AlgoHashRate.SHA256( + web_system_info["hashRate"], HashUnit.SHA256.GH + ).into(self.algo.unit.default) + except KeyError: + pass + + async def _get_uptime(self, web_system_info: dict = None) -> Optional[int]: + if web_system_info is None: + try: + web_system_info = await self.web.system_info() + except APIError: + pass + + if web_system_info is not None: + try: + return web_system_info["uptimeSeconds"] + except KeyError: + pass + + async def _get_hashboards(self, web_system_info: dict = None) -> List[HashBoard]: + if web_system_info is None: + try: + web_system_info = await self.web.system_info() + except APIError: + pass + + if web_system_info is not None: + try: + return [ + HashBoard( + hashrate=AlgoHashRate.SHA256( + web_system_info["hashRate"], HashUnit.SHA256.GH + ).into(self.algo.unit.default), + chip_temp=web_system_info.get("temp"), + temp=web_system_info.get("vrTemp"), + chips=web_system_info.get("asicCount", 1), + expected_chips=self.expected_chips, + missing=False, + active=True, + voltage=web_system_info.get("voltage"), + ) + ] + except KeyError: + pass + return [] + + async def _get_fans(self, web_system_info: dict = None) -> List[Fan]: + if web_system_info is None: + try: + web_system_info = await self.web.system_info() + except APIError: + pass + + if web_system_info is not None: + try: + return [Fan(speed=web_system_info["fanrpm"])] + except KeyError: + pass + return [] + + async def _get_hostname(self, web_system_info: dict = None) -> Optional[str]: + if web_system_info is None: + try: + web_system_info = await self.web.system_info() + except APIError: + pass + + if web_system_info is not None: + try: + return web_system_info["hostname"] + except KeyError: + pass + + async def _get_api_ver(self, web_system_info: dict = None) -> Optional[str]: + if web_system_info is None: + try: + web_system_info = await self.web.system_info() + except APIError: + pass + + if web_system_info is not None: + try: + return web_system_info["version"] + except KeyError: + pass + + async def _get_fw_ver(self, web_system_info: dict = None) -> Optional[str]: + if web_system_info is None: + try: + web_system_info = await self.web.system_info() + except APIError: + pass + + if web_system_info is not None: + try: + return web_system_info["version"] + except KeyError: + pass diff --git a/pyasic/miners/backends/bmminer.py b/pyasic/miners/backends/bmminer.py index 963ef61e..a04462dc 100644 --- a/pyasic/miners/backends/bmminer.py +++ b/pyasic/miners/backends/bmminer.py @@ -109,7 +109,7 @@ class BMMiner(StockFirmware): return self.fw_ver - async def _get_hashrate(self, rpc_summary: dict = None) -> Optional[float]: + async def _get_hashrate(self, rpc_summary: dict = None) -> Optional[AlgoHashRate]: # get hr from API if rpc_summary is None: try: @@ -223,7 +223,9 @@ class BMMiner(StockFirmware): return fans - async def _get_expected_hashrate(self, rpc_stats: dict = None) -> Optional[float]: + async def _get_expected_hashrate( + self, rpc_stats: dict = None + ) -> Optional[AlgoHashRate]: # X19 method, not sure compatibility if rpc_stats is None: try: diff --git a/pyasic/miners/backends/braiins_os.py b/pyasic/miners/backends/braiins_os.py index ab0c75ea..fbbdba37 100644 --- a/pyasic/miners/backends/braiins_os.py +++ b/pyasic/miners/backends/braiins_os.py @@ -26,6 +26,7 @@ from pyasic.config import MinerConfig from pyasic.config.mining import MiningModePowerTune from pyasic.data import AlgoHashRate, Fan, HashBoard, HashUnit from pyasic.data.error_codes import BraiinsOSError, MinerErrorData +from pyasic.data.pools import PoolMetrics, PoolUrl from pyasic.errors import APIError from pyasic.miners.data import ( DataFunction, @@ -39,7 +40,6 @@ from pyasic.rpc.bosminer import BOSMinerRPCAPI from pyasic.ssh.braiins_os import BOSMinerSSH from pyasic.web.braiins_os import BOSerWebAPI, BOSMinerWebAPI from pyasic.web.braiins_os.proto.braiins.bos.v1 import SaveAction -from pyasic.data.pools import PoolMetrics BOSMINER_DATA_LOC = DataLocations( **{ @@ -349,7 +349,7 @@ class BOSMiner(BraiinsOSFirmware): return None return hostname - async def _get_hashrate(self, rpc_summary: dict = None) -> Optional[float]: + async def _get_hashrate(self, rpc_summary: dict = None) -> Optional[AlgoHashRate]: if rpc_summary is None: try: rpc_summary = await self.rpc.summary() @@ -525,7 +525,9 @@ class BOSMiner(BraiinsOSFirmware): except (TypeError, AttributeError): return self.light - async def _get_expected_hashrate(self, rpc_devs: dict = None) -> Optional[float]: + async def _get_expected_hashrate( + self, rpc_devs: dict = None + ) -> Optional[AlgoHashRate]: if rpc_devs is None: try: rpc_devs = await self.rpc.devs() @@ -590,6 +592,8 @@ class BOSMiner(BraiinsOSFirmware): try: pools = rpc_pools.get("POOLS", []) for pool_info in pools: + url = pool_info.get("URL") + pool_url = PoolUrl.from_str(url) if url else None pool_data = PoolMetrics( accepted=pool_info.get("Accepted"), rejected=pool_info.get("Rejected"), @@ -597,17 +601,15 @@ class BOSMiner(BraiinsOSFirmware): remote_failures=pool_info.get("Remote Failures"), active=pool_info.get("Stratum Active"), alive=pool_info.get("Status") == "Alive", - url=pool_info.get("URL"), + url=pool_url, user=pool_info.get("User"), index=pool_info.get("POOL"), - ) pools_data.append(pool_data) except LookupError: pass return pools_data - async def upgrade_firmware(self, file: Path): """ Upgrade the firmware of the BOSMiner device. @@ -866,7 +868,7 @@ class BOSer(BraiinsOSFirmware): except LookupError: pass - async def _get_hashrate(self, rpc_summary: dict = None) -> Optional[float]: + async def _get_hashrate(self, rpc_summary: dict = None) -> Optional[AlgoHashRate]: if rpc_summary is None: try: rpc_summary = await self.rpc.summary() @@ -883,7 +885,7 @@ class BOSer(BraiinsOSFirmware): async def _get_expected_hashrate( self, grpc_miner_details: dict = None - ) -> Optional[float]: + ) -> Optional[AlgoHashRate]: if grpc_miner_details is None: try: grpc_miner_details = await self.web.get_miner_details() diff --git a/pyasic/miners/backends/btminer.py b/pyasic/miners/backends/btminer.py index 7e6b6852..8427bee9 100644 --- a/pyasic/miners/backends/btminer.py +++ b/pyasic/miners/backends/btminer.py @@ -15,9 +15,10 @@ # ------------------------------------------------------------------------------ import logging -from typing import List, Optional -import aiofiles from pathlib import Path +from typing import List, Optional + +import aiofiles from pyasic.config import MinerConfig, MiningModeConfig from pyasic.data import AlgoHashRate, Fan, HashBoard, HashUnit @@ -388,7 +389,7 @@ class BTMiner(StockFirmware): return hostname - async def _get_hashrate(self, rpc_summary: dict = None) -> Optional[float]: + async def _get_hashrate(self, rpc_summary: dict = None) -> Optional[AlgoHashRate]: if rpc_summary is None: try: rpc_summary = await self.rpc.summary() @@ -564,7 +565,9 @@ class BTMiner(StockFirmware): pass return errors - async def _get_expected_hashrate(self, rpc_summary: dict = None) -> Optional[float]: + async def _get_expected_hashrate( + self, rpc_summary: dict = None + ) -> Optional[AlgoHashRate]: if rpc_summary is None: try: rpc_summary = await self.rpc.summary() @@ -675,17 +678,24 @@ class BTMiner(StockFirmware): result = await self.rpc.update_firmware(upgrade_contents) - logging.info("Firmware upgrade process completed successfully for Whatsminer.") + logging.info( + "Firmware upgrade process completed successfully for Whatsminer." + ) return result except FileNotFoundError as e: logging.error(f"File not found during the firmware upgrade process: {e}") raise except ValueError as e: - logging.error(f"Validation error occurred during the firmware upgrade process: {e}") + logging.error( + f"Validation error occurred during the firmware upgrade process: {e}" + ) raise except OSError as e: logging.error(f"OS error occurred during the firmware upgrade process: {e}") raise except Exception as e: - logging.error(f"An unexpected error occurred during the firmware upgrade process: {e}", exc_info=True) + logging.error( + f"An unexpected error occurred during the firmware upgrade process: {e}", + exc_info=True, + ) raise diff --git a/pyasic/miners/backends/cgminer.py b/pyasic/miners/backends/cgminer.py index 53322aed..bb1d1ca4 100644 --- a/pyasic/miners/backends/cgminer.py +++ b/pyasic/miners/backends/cgminer.py @@ -109,7 +109,7 @@ class CGMiner(StockFirmware): return self.fw_ver - async def _get_hashrate(self, rpc_summary: dict = None) -> Optional[float]: + async def _get_hashrate(self, rpc_summary: dict = None) -> Optional[AlgoHashRate]: if rpc_summary is None: try: rpc_summary = await self.rpc.summary() diff --git a/pyasic/miners/backends/epic.py b/pyasic/miners/backends/epic.py index 5ddca5a6..a89a01c7 100644 --- a/pyasic/miners/backends/epic.py +++ b/pyasic/miners/backends/epic.py @@ -14,14 +14,15 @@ # limitations under the License. - # ------------------------------------------------------------------------------ +from pathlib import Path from typing import List, Optional from pyasic.config import MinerConfig from pyasic.data import AlgoHashRate, Fan, HashBoard, HashUnit from pyasic.data.error_codes import MinerErrorData, X19Error +from pyasic.data.pools import PoolMetrics from pyasic.errors import APIError from pyasic.logger import logger -from pyasic.data.pools import PoolMetrics from pyasic.miners.data import DataFunction, DataLocations, DataOptions, WebAPICommand from pyasic.miners.device.firmware import ePICFirmware from pyasic.web.epic import ePICWebAPI @@ -220,7 +221,7 @@ class ePIC(ePICFirmware): except KeyError: pass - async def _get_hashrate(self, web_summary: dict = None) -> Optional[float]: + async def _get_hashrate(self, web_summary: dict = None) -> Optional[AlgoHashRate]: if web_summary is None: try: web_summary = await self.web.summary() @@ -239,7 +240,9 @@ class ePIC(ePICFirmware): except (LookupError, ValueError, TypeError): pass - async def _get_expected_hashrate(self, web_summary: dict = None) -> Optional[float]: + async def _get_expected_hashrate( + self, web_summary: dict = None + ) -> Optional[AlgoHashRate]: if web_summary is None: try: web_summary = await self.web.summary() @@ -449,4 +452,18 @@ class ePIC(ePICFirmware): ) return pool_data except LookupError: - pass \ No newline at end of file + pass + + async def upgrade_firmware(self, file: Path | str, keep_settings: bool = True) -> bool: + + """ + Upgrade the firmware of the ePIC miner device. + + Args: + file (Path | str): The local file path of the firmware to be uploaded. + keep_settings (bool): Whether to keep the current settings after the update. + + Returns: + bool: Whether the firmware update succeeded. + """ + return await self.web.system_update(file=file, keep_settings=keep_settings) \ No newline at end of file diff --git a/pyasic/miners/backends/innosilicon.py b/pyasic/miners/backends/innosilicon.py index 8efe28f2..b6cc88b1 100644 --- a/pyasic/miners/backends/innosilicon.py +++ b/pyasic/miners/backends/innosilicon.py @@ -169,7 +169,7 @@ class Innosilicon(CGMiner): async def _get_hashrate( self, rpc_summary: dict = None, web_get_all: dict = None - ) -> Optional[float]: + ) -> Optional[AlgoHashRate]: if web_get_all: web_get_all = web_get_all["all"] diff --git a/pyasic/miners/backends/luxminer.py b/pyasic/miners/backends/luxminer.py index 0a6a4e38..abaa3664 100644 --- a/pyasic/miners/backends/luxminer.py +++ b/pyasic/miners/backends/luxminer.py @@ -17,6 +17,7 @@ from typing import List, Optional from pyasic.config import MinerConfig from pyasic.data import AlgoHashRate, Fan, HashBoard, HashUnit +from pyasic.data.pools import PoolMetrics, PoolUrl from pyasic.errors import APIError from pyasic.miners.data import DataFunction, DataLocations, DataOptions, RPCAPICommand from pyasic.miners.device.firmware import LuxOSFirmware @@ -51,6 +52,9 @@ LUXMINER_DATA_LOC = DataLocations( str(DataOptions.UPTIME): DataFunction( "_get_uptime", [RPCAPICommand("rpc_stats", "stats")] ), + str(DataOptions.POOLS): DataFunction( + "_get_pools", [RPCAPICommand("rpc_pools", "pools")] + ), } ) @@ -162,7 +166,7 @@ class LUXMiner(LuxOSFirmware): return mac - async def _get_hashrate(self, rpc_summary: dict = None) -> Optional[float]: + async def _get_hashrate(self, rpc_summary: dict = None) -> Optional[AlgoHashRate]: if rpc_summary is None: try: rpc_summary = await self.rpc.summary() @@ -263,7 +267,9 @@ class LUXMiner(LuxOSFirmware): fans.append(Fan()) return fans - async def _get_expected_hashrate(self, rpc_stats: dict = None) -> Optional[float]: + async def _get_expected_hashrate( + self, rpc_stats: dict = None + ) -> Optional[AlgoHashRate]: if rpc_stats is None: try: rpc_stats = await self.rpc.stats() @@ -295,3 +301,33 @@ class LUXMiner(LuxOSFirmware): return int(rpc_stats["STATS"][1]["Elapsed"]) except LookupError: pass + + async def _get_pools(self, rpc_pools: dict = None) -> List[PoolMetrics]: + if rpc_pools is None: + try: + rpc_pools = await self.rpc.pools() + except APIError: + pass + + pools_data = [] + if rpc_pools is not None: + try: + pools = rpc_pools.get("POOLS", []) + for pool_info in pools: + url = pool_info.get("URL") + pool_url = PoolUrl.from_str(url) if url else None + pool_data = PoolMetrics( + accepted=pool_info.get("Accepted"), + rejected=pool_info.get("Rejected"), + get_failures=pool_info.get("Get Failures"), + remote_failures=pool_info.get("Remote Failures"), + active=pool_info.get("Stratum Active"), + alive=pool_info.get("Status") == "Alive", + url=pool_url, + user=pool_info.get("User"), + index=pool_info.get("POOL"), + ) + pools_data.append(pool_data) + except LookupError: + pass + return pools_data diff --git a/pyasic/miners/backends/marathon.py b/pyasic/miners/backends/marathon.py index f9edee32..0c8b1c5f 100644 --- a/pyasic/miners/backends/marathon.py +++ b/pyasic/miners/backends/marathon.py @@ -225,7 +225,7 @@ class MaraMiner(MaraFirmware): except LookupError: pass - async def _get_hashrate(self, web_brief: dict = None) -> Optional[float]: + async def _get_hashrate(self, web_brief: dict = None) -> Optional[AlgoHashRate]: if web_brief is None: try: web_brief = await self.web.brief() @@ -271,7 +271,9 @@ class MaraMiner(MaraFirmware): pass return False - async def _get_expected_hashrate(self, web_brief: dict = None) -> Optional[float]: + async def _get_expected_hashrate( + self, web_brief: dict = None + ) -> Optional[AlgoHashRate]: if web_brief is None: try: web_brief = await self.web.brief() @@ -288,7 +290,7 @@ class MaraMiner(MaraFirmware): async def _get_wattage_limit( self, web_miner_config: dict = None - ) -> Optional[float]: + ) -> Optional[AlgoHashRate]: if web_miner_config is None: try: web_miner_config = await self.web.get_miner_config() diff --git a/pyasic/miners/backends/unknown.py b/pyasic/miners/backends/unknown.py index 5eccae04..a5ecdd3f 100644 --- a/pyasic/miners/backends/unknown.py +++ b/pyasic/miners/backends/unknown.py @@ -15,7 +15,7 @@ from typing import List, Optional, Tuple from pyasic.config import MinerConfig -from pyasic.data import Fan, HashBoard +from pyasic.data import AlgoHashRate, Fan, HashBoard from pyasic.data.error_codes import MinerErrorData from pyasic.miners.base import BaseMiner from pyasic.rpc.unknown import UnknownRPCAPI @@ -80,7 +80,7 @@ class UnknownMiner(BaseMiner): async def _get_hostname(self) -> Optional[str]: return None - async def _get_hashrate(self) -> Optional[float]: + async def _get_hashrate(self) -> Optional[AlgoHashRate]: return None async def _get_hashboards(self) -> List[HashBoard]: @@ -113,7 +113,7 @@ class UnknownMiner(BaseMiner): async def _get_fault_light(self) -> bool: return False - async def _get_expected_hashrate(self) -> Optional[float]: + async def _get_expected_hashrate(self) -> Optional[AlgoHashRate]: return None async def _is_mining(self, *args, **kwargs) -> Optional[bool]: diff --git a/pyasic/miners/backends/vnish.py b/pyasic/miners/backends/vnish.py index 4a560288..b8adc30f 100644 --- a/pyasic/miners/backends/vnish.py +++ b/pyasic/miners/backends/vnish.py @@ -193,7 +193,7 @@ class VNish(VNishFirmware, BMMiner): except KeyError: pass - async def _get_hashrate(self, rpc_summary: dict = None) -> Optional[float]: + async def _get_hashrate(self, rpc_summary: dict = None) -> Optional[AlgoHashRate]: # get hr from API if rpc_summary is None: try: diff --git a/pyasic/miners/backends/whatsminer.py b/pyasic/miners/backends/whatsminer.py index 78d2415b..0654f7fe 100644 --- a/pyasic/miners/backends/whatsminer.py +++ b/pyasic/miners/backends/whatsminer.py @@ -29,4 +29,4 @@ class M3X(BTMiner): class M2X(BTMiner): - pass \ No newline at end of file + pass diff --git a/pyasic/miners/base.py b/pyasic/miners/base.py index 576c0ea4..3ec91703 100644 --- a/pyasic/miners/base.py +++ b/pyasic/miners/base.py @@ -19,7 +19,7 @@ import warnings from typing import List, Optional, Protocol, Tuple, Type, TypeVar, Union from pyasic.config import MinerConfig -from pyasic.data import Fan, HashBoard, MinerData +from pyasic.data import AlgoHashRate, Fan, HashBoard, MinerData from pyasic.data.device import DeviceInfo from pyasic.data.error_codes import MinerErrorData from pyasic.data.pools import PoolMetrics @@ -238,7 +238,7 @@ class MinerProtocol(Protocol): """ return await self._get_hostname() - async def get_hashrate(self) -> Optional[float]: + async def get_hashrate(self) -> Optional[AlgoHashRate]: """Get the hashrate of the miner and return it as a float in TH/s. Returns: @@ -318,7 +318,7 @@ class MinerProtocol(Protocol): """ return await self._get_fault_light() - async def get_expected_hashrate(self) -> Optional[float]: + async def get_expected_hashrate(self) -> Optional[AlgoHashRate]: """Get the nominal hashrate from factory if available. Returns: @@ -362,7 +362,7 @@ class MinerProtocol(Protocol): async def _get_hostname(self) -> Optional[str]: pass - async def _get_hashrate(self) -> Optional[float]: + async def _get_hashrate(self) -> Optional[AlgoHashRate]: pass async def _get_hashboards(self) -> List[HashBoard]: @@ -392,7 +392,7 @@ class MinerProtocol(Protocol): async def _get_fault_light(self) -> Optional[bool]: pass - async def _get_expected_hashrate(self) -> Optional[float]: + async def _get_expected_hashrate(self) -> Optional[AlgoHashRate]: pass async def _is_mining(self) -> Optional[bool]: @@ -574,4 +574,4 @@ class BaseMiner(MinerProtocol): """ return False -AnyMiner = TypeVar("AnyMiner", bound=BaseMiner) \ No newline at end of file +AnyMiner = TypeVar("AnyMiner", bound=BaseMiner) diff --git a/pyasic/miners/bitaxe/__init__.py b/pyasic/miners/bitaxe/__init__.py new file mode 100644 index 00000000..6068242d --- /dev/null +++ b/pyasic/miners/bitaxe/__init__.py @@ -0,0 +1 @@ +from .espminer import * diff --git a/pyasic/miners/bitaxe/espminer/BM/BM1366.py b/pyasic/miners/bitaxe/espminer/BM/BM1366.py new file mode 100644 index 00000000..d2507541 --- /dev/null +++ b/pyasic/miners/bitaxe/espminer/BM/BM1366.py @@ -0,0 +1,6 @@ +from pyasic.miners.backends.bitaxe import BitAxe +from pyasic.miners.device.models.bitaxe import Ultra + + +class BitAxeUltra(BitAxe, Ultra): + pass diff --git a/pyasic/miners/bitaxe/espminer/BM/BM1368.py b/pyasic/miners/bitaxe/espminer/BM/BM1368.py new file mode 100644 index 00000000..ea2e3b7b --- /dev/null +++ b/pyasic/miners/bitaxe/espminer/BM/BM1368.py @@ -0,0 +1,6 @@ +from pyasic.miners.backends.bitaxe import BitAxe +from pyasic.miners.device.models.bitaxe import Supra + + +class BitAxeSupra(BitAxe, Supra): + pass diff --git a/pyasic/miners/bitaxe/espminer/BM/BM1397.py b/pyasic/miners/bitaxe/espminer/BM/BM1397.py new file mode 100644 index 00000000..722b1d35 --- /dev/null +++ b/pyasic/miners/bitaxe/espminer/BM/BM1397.py @@ -0,0 +1,6 @@ +from pyasic.miners.backends.bitaxe import BitAxe +from pyasic.miners.device.models.bitaxe import Max + + +class BitAxeMax(BitAxe, Max): + pass diff --git a/pyasic/miners/bitaxe/espminer/BM/__init__.py b/pyasic/miners/bitaxe/espminer/BM/__init__.py new file mode 100644 index 00000000..9926a677 --- /dev/null +++ b/pyasic/miners/bitaxe/espminer/BM/__init__.py @@ -0,0 +1,3 @@ +from .BM1366 import BitAxeUltra +from .BM1368 import BitAxeSupra +from .BM1397 import BitAxeMax diff --git a/pyasic/miners/bitaxe/espminer/__init__.py b/pyasic/miners/bitaxe/espminer/__init__.py new file mode 100644 index 00000000..dc06b2e0 --- /dev/null +++ b/pyasic/miners/bitaxe/espminer/__init__.py @@ -0,0 +1 @@ +from .BM import * diff --git a/pyasic/miners/device/makes.py b/pyasic/miners/device/makes.py index 2d8433a4..6bfbe40b 100644 --- a/pyasic/miners/device/makes.py +++ b/pyasic/miners/device/makes.py @@ -44,3 +44,7 @@ class AuradineMake(BaseMiner): class ePICMake(BaseMiner): make = MinerMake.EPIC + + +class BitAxeMake(BaseMiner): + make = MinerMake.BITAXE diff --git a/pyasic/miners/device/models/antminer/X3/L3.py b/pyasic/miners/device/models/antminer/X3/L3.py index 82bb7172..bd5ba911 100644 --- a/pyasic/miners/device/models/antminer/X3/L3.py +++ b/pyasic/miners/device/models/antminer/X3/L3.py @@ -18,6 +18,6 @@ from pyasic.miners.device.makes import AntMinerMake class L3Plus(AntMinerMake): - raw_model = MinerModel.ANTMINER + raw_model = MinerModel.ANTMINER.L3Plus expected_chips = 72 diff --git a/pyasic/miners/device/models/bitaxe/BM/BM1366.py b/pyasic/miners/device/models/bitaxe/BM/BM1366.py new file mode 100644 index 00000000..6db1ad16 --- /dev/null +++ b/pyasic/miners/device/models/bitaxe/BM/BM1366.py @@ -0,0 +1,10 @@ +from pyasic.device.models import MinerModel +from pyasic.miners.device.makes import BitAxeMake + + +class Ultra(BitAxeMake): + raw_model = MinerModel.BITAXE.BM1366 + + expected_hashboards = 1 + expected_chips = 1 + expected_fans = 1 diff --git a/pyasic/miners/device/models/bitaxe/BM/BM1368.py b/pyasic/miners/device/models/bitaxe/BM/BM1368.py new file mode 100644 index 00000000..76cf63c9 --- /dev/null +++ b/pyasic/miners/device/models/bitaxe/BM/BM1368.py @@ -0,0 +1,10 @@ +from pyasic.device.models import MinerModel +from pyasic.miners.device.makes import BitAxeMake + + +class Supra(BitAxeMake): + raw_model = MinerModel.BITAXE.BM1368 + + expected_hashboards = 1 + expected_chips = 1 + expected_fans = 1 diff --git a/pyasic/miners/device/models/bitaxe/BM/BM1397.py b/pyasic/miners/device/models/bitaxe/BM/BM1397.py new file mode 100644 index 00000000..97230f17 --- /dev/null +++ b/pyasic/miners/device/models/bitaxe/BM/BM1397.py @@ -0,0 +1,10 @@ +from pyasic.device.models import MinerModel +from pyasic.miners.device.makes import BitAxeMake + + +class Max(BitAxeMake): + raw_model = MinerModel.BITAXE.BM1397 + + expected_hashboards = 1 + expected_chips = 1 + expected_fans = 1 diff --git a/pyasic/miners/device/models/bitaxe/BM/__init__.py b/pyasic/miners/device/models/bitaxe/BM/__init__.py new file mode 100644 index 00000000..b2c1b2c0 --- /dev/null +++ b/pyasic/miners/device/models/bitaxe/BM/__init__.py @@ -0,0 +1,3 @@ +from .BM1366 import Ultra +from .BM1368 import Supra +from .BM1397 import Max diff --git a/pyasic/miners/device/models/bitaxe/__init__.py b/pyasic/miners/device/models/bitaxe/__init__.py new file mode 100644 index 00000000..dc06b2e0 --- /dev/null +++ b/pyasic/miners/device/models/bitaxe/__init__.py @@ -0,0 +1 @@ +from .BM import * diff --git a/pyasic/miners/factory.py b/pyasic/miners/factory.py index 7a338029..bff39771 100644 --- a/pyasic/miners/factory.py +++ b/pyasic/miners/factory.py @@ -31,8 +31,10 @@ from pyasic.miners.antminer import * from pyasic.miners.auradine import * from pyasic.miners.avalonminer import * from pyasic.miners.backends import * +from pyasic.miners.backends.bitaxe import BitAxe from pyasic.miners.backends.unknown import UnknownMiner from pyasic.miners.base import AnyMiner +from pyasic.miners.bitaxe import * from pyasic.miners.blockminer import * from pyasic.miners.device.makes import * from pyasic.miners.goldshell import * @@ -53,6 +55,7 @@ class MinerTypes(enum.Enum): EPIC = 9 AURADINE = 10 MARATHON = 11 + BITAXE = 12 MINER_CLASSES = { @@ -383,6 +386,7 @@ MINER_CLASSES = { "ANTMINER S19J PRO": VNishS19jPro, "ANTMINER S19A": VNishS19a, "ANTMINER S19A PRO": VNishS19aPro, + "ANTMINER S19 PRO HYD.": VNishS19ProHydro, "ANTMINER T19": VNishT19, "ANTMINER S21": VNishS21, }, @@ -438,6 +442,12 @@ MINER_CLASSES = { "ANTMINER S21": MaraS21, "ANTMINER T21": MaraT21, }, + MinerTypes.BITAXE: { + None: BitAxe, + "BM1368": BitAxeSupra, + "BM1366": BitAxeUltra, + "BM1397": BitAxeMax, + }, } @@ -514,6 +524,7 @@ class MinerFactory: MinerTypes.LUX_OS: self.get_miner_model_luxos, MinerTypes.AURADINE: self.get_miner_model_auradine, MinerTypes.MARATHON: self.get_miner_model_marathon, + MinerTypes.BITAXE: self.get_miner_model_bitaxe, } fn = miner_model_fns.get(miner_type) @@ -595,6 +606,8 @@ class MinerFactory: return MinerTypes.WHATSMINER if "Braiins OS" in web_text: return MinerTypes.BRAIINS_OS + if "AxeOS" in web_text: + return MinerTypes.BITAXE if "cloud-box" in web_text: return MinerTypes.GOLDSHELL if "AnthillOS" in web_text: @@ -1008,6 +1021,18 @@ class MinerFactory: except (TypeError, LookupError): pass + async def get_miner_model_bitaxe(self, ip: str) -> str | None: + web_json_data = await self.send_web_command(ip, "/api/system/info") + + try: + miner_model = web_json_data["ASICModel"] + if miner_model == "": + return None + + return miner_model + except (TypeError, LookupError): + pass + miner_factory = MinerFactory() diff --git a/pyasic/ssh/braiins_os.py b/pyasic/ssh/braiins_os.py index 28ad000d..6dee3502 100644 --- a/pyasic/ssh/braiins_os.py +++ b/pyasic/ssh/braiins_os.py @@ -92,4 +92,4 @@ class BOSMinerSSH(BaseSSH): Returns: str: Status of the LED. """ - return await self.send_command("cat /sys/class/leds/'Red LED'/delay_off") \ No newline at end of file + return await self.send_command("cat /sys/class/leds/'Red LED'/delay_off") diff --git a/pyasic/web/bitaxe.py b/pyasic/web/bitaxe.py new file mode 100644 index 00000000..6f5c5de7 --- /dev/null +++ b/pyasic/web/bitaxe.py @@ -0,0 +1,96 @@ +from __future__ import annotations + +import asyncio +import json +from typing import Any + +import httpx + +from pyasic import APIError, settings +from pyasic.web.base import BaseWebAPI + + +class BitAxeWebAPI(BaseWebAPI): + async def send_command( + self, + command: str | bytes, + ignore_errors: bool = False, + allow_warning: bool = True, + privileged: bool = False, + **parameters: Any, + ) -> dict: + url = f"http://{self.ip}:{self.port}/api/{command}" + try: + async with httpx.AsyncClient( + transport=settings.transport(), + ) as client: + if parameters.get("post", False): + parameters.pop("post") + data = await client.post( + url, + timeout=settings.get("api_function_timeout", 3), + json=parameters, + ) + elif parameters.get("patch", False): + parameters.pop("patch") + data = await client.patch( + url, + timeout=settings.get("api_function_timeout", 3), + json=parameters, + ) + else: + data = await client.get(url) + except httpx.HTTPError: + pass + else: + if data.status_code == 200: + try: + return data.json() + except json.decoder.JSONDecodeError: + pass + + async def multicommand( + self, *commands: str, ignore_errors: bool = False, allow_warning: bool = True + ) -> dict: + """Execute multiple commands simultaneously on the BitAxe miner. + + Args: + *commands (str): Commands to execute. + ignore_errors (bool): Whether to ignore errors during command execution. + allow_warning (bool): Whether to proceed despite warnings. + + Returns: + dict: A dictionary containing responses for all commands executed. + """ + tasks = {} + # send all commands individually + for cmd in commands: + tasks[cmd] = asyncio.create_task( + self.send_command(cmd, allow_warning=allow_warning) + ) + + await asyncio.gather(*[tasks[cmd] for cmd in tasks], return_exceptions=True) + + data = {"multicommand": True} + for cmd in tasks: + try: + result = tasks[cmd].result() + if result is None or result == {}: + result = {} + data[cmd] = result + except APIError: + pass + + return data + + async def system_info(self): + return await self.send_command("system/info") + + async def swarm_info(self): + return await self.send_command("swarm/info") + + async def restart(self): + return await self.send_command("system/restart", post=True) + + async def update_settings(self, **config): + return await self.send_command("system", patch=True, **config) diff --git a/pyasic/web/epic.py b/pyasic/web/epic.py index 8f0e1b41..4a72ec93 100644 --- a/pyasic/web/epic.py +++ b/pyasic/web/epic.py @@ -15,9 +15,12 @@ # ------------------------------------------------------------------------------ from __future__ import annotations +import hashlib import json +from pathlib import Path from typing import Any +import aiofiles import httpx from pyasic import settings @@ -46,6 +49,14 @@ class ePICWebAPI(BaseWebAPI): async with httpx.AsyncClient(transport=settings.transport()) as client: for retry_cnt in range(settings.get("get_data_retries", 1)): try: + if parameters.get("form") is not None: + form_data = parameters["form"] + form_data.add_field("password", self.pwd) + response = await client.post( + f"http://{self.ip}:{self.port}/{command}", + timeout=5, + data=form_data, + ) if post: response = await client.post( f"http://{self.ip}:{self.port}/{command}", @@ -135,3 +146,22 @@ class ePICWebAPI(BaseWebAPI): async def capabilities(self) -> dict: return await self.send_command("capabilities") + + async def system_update(self, file: Path | str, keep_settings: bool = True): + """Perform a system update by uploading a firmware file and sending a + command to initiate the update.""" + + # calculate the SHA256 checksum of the firmware file + sha256_hash = hashlib.sha256() + async with aiofiles.open(str(file), "rb") as f: + while chunk := await f.read(8192): + sha256_hash.update(chunk) + checksum = sha256_hash.hexdigest() + + # prepare the multipart/form-data request + form_data = aiohttp.FormData() + form_data.add_field("checksum", checksum) + form_data.add_field("keepsettings", str(keep_settings).lower()) + form_data.add_field("update.zip", open(file, "rb"), filename="update.zip") + + await self.send_command("systemupdate", form=form_data) diff --git a/pyproject.toml b/pyproject.toml index 47937b3d..2de66080 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "pyasic" -version = "0.57.6" +version = "0.58.1" description = "A simplified and standardized interface for Bitcoin ASICs." authors = ["UpstreamData "] repository = "https://github.com/UpstreamData/pyasic" diff --git a/tests/miners_tests/__init__.py b/tests/miners_tests/__init__.py index 6beb5c49..523271a2 100644 --- a/tests/miners_tests/__init__.py +++ b/tests/miners_tests/__init__.py @@ -55,7 +55,6 @@ class MinersTest(unittest.TestCase): "expected_hashrate", "uptime", "wattage", - "voltage", "wattage_limit", "pools", ]