Compare commits
34 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2bd031b33d | ||
|
|
e2f07818cc | ||
|
|
75056cfff5 | ||
|
|
7fbcb0dbd2 | ||
|
|
7329aeace2 | ||
|
|
e8c3953106 | ||
|
|
a1a7562bdb | ||
|
|
b2726c77a0 | ||
|
|
68299fa54d | ||
|
|
1466039e08 | ||
|
|
0aa72c6c85 | ||
|
|
24134a5991 | ||
|
|
038208efa6 | ||
|
|
7e319b79df | ||
|
|
a0fdec3ce5 | ||
|
|
1a8928de18 | ||
|
|
bce0058930 | ||
|
|
850656fce4 | ||
|
|
8bb35d6d7c | ||
|
|
e85f06dbc2 | ||
|
|
a566801316 | ||
|
|
e1a9cc5d19 | ||
|
|
27bb06de2b | ||
|
|
debd4d2d4d | ||
|
|
56ad6cbc6f | ||
|
|
3fa54213bf | ||
|
|
076958ec0e | ||
|
|
5319089ebe | ||
|
|
76a77b51e8 | ||
|
|
b099ff45d2 | ||
|
|
9bc3cc221a | ||
|
|
6418c2e102 | ||
|
|
aa9f3b2c45 | ||
|
|
bb1c98f061 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -7,3 +7,4 @@ pyvenv.cfg
|
||||
bin/
|
||||
lib/
|
||||
.idea/
|
||||
.vs/
|
||||
16
docs/miners/avalonminer/Q.md
Normal file
16
docs/miners/avalonminer/Q.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# pyasic
|
||||
## Q Models
|
||||
|
||||
## Avalon Q Home (Stock)
|
||||
|
||||
- [ ] Shutdowns
|
||||
- [ ] Power Modes
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.avalonminer.cgminer.Q.Q.CGMinerAvalonQHome
|
||||
handler: python
|
||||
options:
|
||||
show_root_heading: false
|
||||
heading_level: 0
|
||||
|
||||
16
docs/miners/goldshell/Byte.md
Normal file
16
docs/miners/goldshell/Byte.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# pyasic
|
||||
## byte Models
|
||||
|
||||
## Byte (Stock)
|
||||
|
||||
- [ ] Shutdowns
|
||||
- [ ] Power Modes
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.goldshell.bfgminer.byte.byte.GoldshellByte
|
||||
handler: python
|
||||
options:
|
||||
show_root_heading: false
|
||||
heading_level: 0
|
||||
|
||||
16
docs/miners/goldshell/MiniDoge.md
Normal file
16
docs/miners/goldshell/MiniDoge.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# pyasic
|
||||
## Mini Doge Models
|
||||
|
||||
## Mini Doge (Stock)
|
||||
|
||||
- [ ] Shutdowns
|
||||
- [ ] Power Modes
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.goldshell.bfgminer.MiniDoge.MiniDoge.GoldshellMiniDoge
|
||||
handler: python
|
||||
options:
|
||||
show_root_heading: false
|
||||
heading_level: 0
|
||||
|
||||
16
docs/miners/goldshell/mini_doge.md
Normal file
16
docs/miners/goldshell/mini_doge.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# pyasic
|
||||
## mini_doge Models
|
||||
|
||||
## Mini Doge (Stock)
|
||||
|
||||
- [ ] Shutdowns
|
||||
- [ ] Power Modes
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.goldshell.bfgminer.mini_doge.mini_doge.GoldshellMiniDoge
|
||||
handler: python
|
||||
options:
|
||||
show_root_heading: false
|
||||
heading_level: 0
|
||||
|
||||
16
docs/miners/iceriver/ALX.md
Normal file
16
docs/miners/iceriver/ALX.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# pyasic
|
||||
## ALX Models
|
||||
|
||||
## AL3 (Stock)
|
||||
|
||||
- [ ] Shutdowns
|
||||
- [ ] Power Modes
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.iceriver.iceminer.ALX.AL3.IceRiverAL3
|
||||
handler: python
|
||||
options:
|
||||
show_root_heading: false
|
||||
heading_level: 0
|
||||
|
||||
@@ -38,6 +38,7 @@ details {
|
||||
<details>
|
||||
<summary>X7 Series:</summary>
|
||||
<ul>
|
||||
<li><a href="../antminer/X7#l7-stock">L7 (Stock)</a></li>
|
||||
<li><a href="../antminer/X7#l7-stock">L7 (Stock)</a></li>
|
||||
<li><a href="../antminer/X7#k7-stock">K7 (Stock)</a></li>
|
||||
<li><a href="../antminer/X7#d7-stock">D7 (Stock)</a></li>
|
||||
@@ -53,6 +54,7 @@ details {
|
||||
<li><a href="../antminer/X9#s9j-stock">S9j (Stock)</a></li>
|
||||
<li><a href="../antminer/X9#t9-stock">T9 (Stock)</a></li>
|
||||
<li><a href="../antminer/X9#l9-stock">L9 (Stock)</a></li>
|
||||
<li><a href="../antminer/X9#l9-stock">L9 (Stock)</a></li>
|
||||
</ul>
|
||||
</details>
|
||||
<details>
|
||||
@@ -107,6 +109,7 @@ details {
|
||||
<li><a href="../antminer/X21#s21-stock">S21 (Stock)</a></li>
|
||||
<li><a href="../antminer/X21#s21_1-stock">S21+ (Stock)</a></li>
|
||||
<li><a href="../antminer/X21#s21_1-hydro-stock">S21+ Hydro (Stock)</a></li>
|
||||
<li><a href="../antminer/X21#s21_1-hydro-stock">S21+ Hydro (Stock)</a></li>
|
||||
<li><a href="../antminer/X21#s21-pro-stock">S21 Pro (Stock)</a></li>
|
||||
<li><a href="../antminer/X21#t21-stock">T21 (Stock)</a></li>
|
||||
<li><a href="../antminer/X21#s21-hydro-stock">S21 Hydro (Stock)</a></li>
|
||||
@@ -621,6 +624,18 @@ details {
|
||||
<li><a href="../goldshell/XBox#kd-box-pro-stock">KD Box Pro (Stock)</a></li>
|
||||
</ul>
|
||||
</details>
|
||||
<details>
|
||||
<summary>byte Series:</summary>
|
||||
<ul>
|
||||
<li><a href="../goldshell/byte#byte-stock">Byte (Stock)</a></li>
|
||||
</ul>
|
||||
</details>
|
||||
<details>
|
||||
<summary>mini_doge Series:</summary>
|
||||
<ul>
|
||||
<li><a href="../goldshell/mini_doge#mini-doge-stock">Mini Doge (Stock)</a></li>
|
||||
</ul>
|
||||
</details>
|
||||
</ul>
|
||||
</details>
|
||||
<details>
|
||||
@@ -734,6 +749,7 @@ details {
|
||||
<li><a href="../antminer/X19#s19a-pro-vnish">S19a Pro (VNish)</a></li>
|
||||
<li><a href="../antminer/X19#s19-pro-a-vnish">S19 Pro A (VNish)</a></li>
|
||||
<li><a href="../antminer/X19#s19-pro-hydro-vnish">S19 Pro Hydro (VNish)</a></li>
|
||||
<li><a href="../antminer/X19#s19-pro-hydro-vnish">S19 Pro Hydro (VNish)</a></li>
|
||||
<li><a href="../antminer/X19#s19k-pro-vnish">S19k Pro (VNish)</a></li>
|
||||
<li><a href="../antminer/X19#t19-vnish">T19 (VNish)</a></li>
|
||||
</ul>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,7 +5,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus_Plus.BTMinerM50SPlusPlusVK10
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus_Plus.BTMinerM50SPlusPlusVK20
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus_Plus.BTMinerM50SPlusPlusVK30
|
||||
@@ -44,7 +44,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus_Plus.BTMinerM50SPlusPlusVK40
|
||||
@@ -57,7 +57,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus_Plus.BTMinerM50SPlusPlusVK50
|
||||
@@ -70,7 +70,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus_Plus.BTMinerM50SPlusPlusVK60
|
||||
@@ -83,7 +83,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus_Plus.BTMinerM50SPlusPlusVL20
|
||||
@@ -96,7 +96,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus_Plus.BTMinerM50SPlusPlusVL30
|
||||
@@ -109,7 +109,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus_Plus.BTMinerM50SPlusPlusVL40
|
||||
@@ -122,7 +122,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus_Plus.BTMinerM50SPlusPlusVL50
|
||||
@@ -135,7 +135,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus_Plus.BTMinerM50SPlusPlusVL60
|
||||
@@ -148,7 +148,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus.BTMinerM50SPlusVH30
|
||||
@@ -161,7 +161,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus.BTMinerM50SPlusVH40
|
||||
@@ -174,7 +174,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus.BTMinerM50SPlusVJ30
|
||||
@@ -187,7 +187,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus.BTMinerM50SPlusVJ40
|
||||
@@ -200,7 +200,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus.BTMinerM50SPlusVJ60
|
||||
@@ -213,7 +213,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus.BTMinerM50SPlusVK10
|
||||
@@ -226,7 +226,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus.BTMinerM50SPlusVK20
|
||||
@@ -239,7 +239,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus.BTMinerM50SPlusVK30
|
||||
@@ -252,7 +252,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus.BTMinerM50SPlusVL10
|
||||
@@ -265,7 +265,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus.BTMinerM50SPlusVL20
|
||||
@@ -278,7 +278,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S_Plus.BTMinerM50SPlusVL30
|
||||
@@ -291,7 +291,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVH10
|
||||
@@ -304,7 +304,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVH20
|
||||
@@ -317,7 +317,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVH30
|
||||
@@ -330,7 +330,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVH40
|
||||
@@ -343,7 +343,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVH50
|
||||
@@ -356,7 +356,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVJ10
|
||||
@@ -369,7 +369,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVJ20
|
||||
@@ -382,7 +382,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVJ30
|
||||
@@ -395,7 +395,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVJ40
|
||||
@@ -408,7 +408,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVJ50
|
||||
@@ -421,7 +421,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVK10
|
||||
@@ -434,7 +434,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVK20
|
||||
@@ -447,7 +447,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVK30
|
||||
@@ -460,7 +460,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVK50
|
||||
@@ -473,7 +473,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVK60
|
||||
@@ -486,7 +486,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVK70
|
||||
@@ -499,7 +499,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVK80
|
||||
@@ -512,7 +512,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVL20
|
||||
@@ -525,7 +525,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50S.BTMinerM50SVL30
|
||||
@@ -538,7 +538,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VE30
|
||||
@@ -551,7 +551,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VG30
|
||||
@@ -564,7 +564,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH10
|
||||
@@ -577,7 +577,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH20
|
||||
@@ -590,7 +590,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH30
|
||||
@@ -603,7 +603,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH40
|
||||
@@ -616,7 +616,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH50
|
||||
@@ -629,7 +629,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH60
|
||||
@@ -642,7 +642,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH70
|
||||
@@ -655,7 +655,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH80
|
||||
@@ -668,7 +668,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VH90
|
||||
@@ -681,7 +681,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VJ10
|
||||
@@ -694,7 +694,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VJ20
|
||||
@@ -707,7 +707,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VJ30
|
||||
@@ -720,7 +720,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VJ40
|
||||
@@ -733,7 +733,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VJ60
|
||||
@@ -746,7 +746,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VK40
|
||||
@@ -759,7 +759,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M50.BTMinerM50VK50
|
||||
@@ -772,7 +772,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M52S_Plus_Plus.BTMinerM52SPlusPlusVL10
|
||||
@@ -785,7 +785,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M52S.BTMinerM52SVK30
|
||||
@@ -798,7 +798,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M53H.BTMinerM53HVH10
|
||||
@@ -811,7 +811,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M53S_Plus_Plus.BTMinerM53SPlusPlusVK10
|
||||
@@ -824,7 +824,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M53S_Plus_Plus.BTMinerM53SPlusPlusVK20
|
||||
@@ -837,7 +837,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M53S_Plus_Plus.BTMinerM53SPlusPlusVK30
|
||||
@@ -850,7 +850,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M53S_Plus_Plus.BTMinerM53SPlusPlusVK50
|
||||
@@ -863,7 +863,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M53S_Plus_Plus.BTMinerM53SPlusPlusVL10
|
||||
@@ -876,7 +876,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M53S_Plus_Plus.BTMinerM53SPlusPlusVL30
|
||||
@@ -889,7 +889,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M53S_Plus.BTMinerM53SPlusVJ30
|
||||
@@ -902,7 +902,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M53S_Plus.BTMinerM53SPlusVJ40
|
||||
@@ -915,7 +915,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M53S_Plus.BTMinerM53SPlusVJ50
|
||||
@@ -928,7 +928,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M53S_Plus.BTMinerM53SPlusVK30
|
||||
@@ -941,7 +941,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M53S.BTMinerM53SVH20
|
||||
@@ -954,7 +954,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M53S.BTMinerM53SVH30
|
||||
@@ -967,7 +967,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M53S.BTMinerM53SVJ30
|
||||
@@ -980,7 +980,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M53S.BTMinerM53SVJ40
|
||||
@@ -993,7 +993,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M53S.BTMinerM53SVK30
|
||||
@@ -1006,7 +1006,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M53.BTMinerM53VH30
|
||||
@@ -1019,7 +1019,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M53.BTMinerM53VH40
|
||||
@@ -1032,7 +1032,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M53.BTMinerM53VH50
|
||||
@@ -1045,7 +1045,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M53.BTMinerM53VK30
|
||||
@@ -1058,7 +1058,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M53.BTMinerM53VK60
|
||||
@@ -1071,7 +1071,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M54S_Plus_Plus.BTMinerM54SPlusPlusVK30
|
||||
@@ -1084,7 +1084,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M54S_Plus_Plus.BTMinerM54SPlusPlusVL30
|
||||
@@ -1097,7 +1097,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M54S_Plus_Plus.BTMinerM54SPlusPlusVL40
|
||||
@@ -1110,7 +1110,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M56S_Plus_Plus.BTMinerM56SPlusPlusVK10
|
||||
@@ -1123,7 +1123,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M56S_Plus_Plus.BTMinerM56SPlusPlusVK30
|
||||
@@ -1136,7 +1136,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M56S_Plus_Plus.BTMinerM56SPlusPlusVK40
|
||||
@@ -1149,7 +1149,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M56S_Plus_Plus.BTMinerM56SPlusPlusVK50
|
||||
@@ -1162,7 +1162,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M56S_Plus.BTMinerM56SPlusVJ30
|
||||
@@ -1175,7 +1175,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M56S_Plus.BTMinerM56SPlusVK30
|
||||
@@ -1188,7 +1188,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M56S_Plus.BTMinerM56SPlusVK40
|
||||
@@ -1201,7 +1201,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M56S_Plus.BTMinerM56SPlusVK50
|
||||
@@ -1214,7 +1214,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M56S.BTMinerM56SVH30
|
||||
@@ -1227,7 +1227,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M56S.BTMinerM56SVJ30
|
||||
@@ -1240,7 +1240,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M56S.BTMinerM56SVJ40
|
||||
@@ -1253,7 +1253,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M56.BTMinerM56VH30
|
||||
@@ -1266,7 +1266,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M5X.M59.BTMinerM59VH30
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M60S_Plus_Plus.BTMinerM60SPlusPlusVL30
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M60S_Plus_Plus.BTMinerM60SPlusPlusVL40
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M60S_Plus.BTMinerM60SPlusVK30
|
||||
@@ -44,7 +44,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M60S_Plus.BTMinerM60SPlusVK40
|
||||
@@ -57,7 +57,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M60S_Plus.BTMinerM60SPlusVK50
|
||||
@@ -70,7 +70,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M60S_Plus.BTMinerM60SPlusVK60
|
||||
@@ -83,7 +83,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M60S_Plus.BTMinerM60SPlusVK70
|
||||
@@ -96,7 +96,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M60S_Plus.BTMinerM60SPlusVL10
|
||||
@@ -109,7 +109,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M60S_Plus.BTMinerM60SPlusVL30
|
||||
@@ -122,7 +122,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M60S_Plus.BTMinerM60SPlusVL40
|
||||
@@ -135,7 +135,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M60S_Plus.BTMinerM60SPlusVL50
|
||||
@@ -148,7 +148,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M60S_Plus.BTMinerM60SPlusVL60
|
||||
@@ -161,7 +161,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M60S.BTMinerM60SVK10
|
||||
@@ -174,7 +174,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M60S.BTMinerM60SVK20
|
||||
@@ -187,7 +187,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M60S.BTMinerM60SVK30
|
||||
@@ -200,7 +200,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M60S.BTMinerM60SVK40
|
||||
@@ -213,7 +213,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M60S.BTMinerM60SVL10
|
||||
@@ -226,7 +226,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M60S.BTMinerM60SVL20
|
||||
@@ -239,7 +239,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M60S.BTMinerM60SVL30
|
||||
@@ -252,7 +252,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M60S.BTMinerM60SVL40
|
||||
@@ -265,7 +265,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M60S.BTMinerM60SVL50
|
||||
@@ -278,7 +278,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M60S.BTMinerM60SVL60
|
||||
@@ -291,7 +291,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M60S.BTMinerM60SVL70
|
||||
@@ -304,7 +304,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M60.BTMinerM60VK10
|
||||
@@ -317,7 +317,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M60.BTMinerM60VK20
|
||||
@@ -330,7 +330,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M60.BTMinerM60VK30
|
||||
@@ -343,7 +343,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M60.BTMinerM60VK40
|
||||
@@ -356,7 +356,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M60.BTMinerM60VK6A
|
||||
@@ -369,7 +369,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M60.BTMinerM60VL10
|
||||
@@ -382,7 +382,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M60.BTMinerM60VL20
|
||||
@@ -395,7 +395,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M60.BTMinerM60VL30
|
||||
@@ -408,7 +408,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M60.BTMinerM60VL40
|
||||
@@ -421,7 +421,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M60.BTMinerM60VL50
|
||||
@@ -434,7 +434,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M61S_Plus.BTMinerM61SPlusVL30
|
||||
@@ -447,7 +447,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M61S.BTMinerM61SVL10
|
||||
@@ -460,7 +460,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M61S.BTMinerM61SVL20
|
||||
@@ -473,7 +473,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M61S.BTMinerM61SVL30
|
||||
@@ -486,7 +486,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M61.BTMinerM61VK10
|
||||
@@ -499,7 +499,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M61.BTMinerM61VK20
|
||||
@@ -512,7 +512,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M61.BTMinerM61VK30
|
||||
@@ -525,7 +525,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M61.BTMinerM61VK40
|
||||
@@ -538,7 +538,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M61.BTMinerM61VL10
|
||||
@@ -551,7 +551,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M61.BTMinerM61VL30
|
||||
@@ -564,7 +564,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M61.BTMinerM61VL40
|
||||
@@ -577,7 +577,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M61.BTMinerM61VL50
|
||||
@@ -590,7 +590,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M61.BTMinerM61VL60
|
||||
@@ -603,7 +603,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M62S_Plus.BTMinerM62SPlusVK30
|
||||
@@ -616,7 +616,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M63S_Plus_Plus.BTMinerM63SPlusPlusVL20
|
||||
@@ -629,7 +629,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M63S_Plus.BTMinerM63SPlusVK30
|
||||
@@ -642,7 +642,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M63S_Plus.BTMinerM63SPlusVL10
|
||||
@@ -655,7 +655,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M63S_Plus.BTMinerM63SPlusVL20
|
||||
@@ -668,7 +668,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M63S_Plus.BTMinerM63SPlusVL30
|
||||
@@ -681,7 +681,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M63S_Plus.BTMinerM63SPlusVL50
|
||||
@@ -694,7 +694,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M63S.BTMinerM63SVK10
|
||||
@@ -707,7 +707,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M63S.BTMinerM63SVK20
|
||||
@@ -720,7 +720,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M63S.BTMinerM63SVK30
|
||||
@@ -733,7 +733,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M63S.BTMinerM63SVK60
|
||||
@@ -746,7 +746,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M63S.BTMinerM63SVL10
|
||||
@@ -759,7 +759,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M63S.BTMinerM63SVL50
|
||||
@@ -772,7 +772,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M63S.BTMinerM63SVL60
|
||||
@@ -785,7 +785,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M63.BTMinerM63VK10
|
||||
@@ -798,7 +798,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M63.BTMinerM63VK20
|
||||
@@ -811,7 +811,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M63.BTMinerM63VK30
|
||||
@@ -824,7 +824,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M63.BTMinerM63VL10
|
||||
@@ -837,7 +837,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M63.BTMinerM63VL30
|
||||
@@ -850,7 +850,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M64S.BTMinerM64SVL30
|
||||
@@ -863,7 +863,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M64.BTMinerM64VL30
|
||||
@@ -876,7 +876,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M64.BTMinerM64VL40
|
||||
@@ -889,7 +889,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M65S_Plus.BTMinerM65SPlusVK30
|
||||
@@ -902,7 +902,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M65S.BTMinerM65SVK20
|
||||
@@ -915,7 +915,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M65S.BTMinerM65SVL60
|
||||
@@ -928,7 +928,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M66S_Plus_Plus.BTMinerM66SPlusPlusVL20
|
||||
@@ -941,7 +941,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M66S_Plus.BTMinerM66SPlusVK30
|
||||
@@ -954,7 +954,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M66S_Plus.BTMinerM66SPlusVL10
|
||||
@@ -967,7 +967,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M66S_Plus.BTMinerM66SPlusVL20
|
||||
@@ -980,7 +980,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M66S_Plus.BTMinerM66SPlusVL30
|
||||
@@ -993,7 +993,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M66S_Plus.BTMinerM66SPlusVL40
|
||||
@@ -1006,7 +1006,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M66S_Plus.BTMinerM66SPlusVL60
|
||||
@@ -1019,7 +1019,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M66S.BTMinerM66SVK20
|
||||
@@ -1032,7 +1032,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M66S.BTMinerM66SVK30
|
||||
@@ -1045,7 +1045,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M66S.BTMinerM66SVK40
|
||||
@@ -1058,7 +1058,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M66S.BTMinerM66SVK50
|
||||
@@ -1071,7 +1071,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M66S.BTMinerM66SVK60
|
||||
@@ -1084,7 +1084,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M66S.BTMinerM66SVL10
|
||||
@@ -1097,7 +1097,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M66S.BTMinerM66SVL20
|
||||
@@ -1110,7 +1110,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M66S.BTMinerM66SVL30
|
||||
@@ -1123,7 +1123,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M66S.BTMinerM66SVL40
|
||||
@@ -1136,7 +1136,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M66S.BTMinerM66SVL50
|
||||
@@ -1149,7 +1149,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M66.BTMinerM66VK20
|
||||
@@ -1162,7 +1162,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M66.BTMinerM66VK30
|
||||
@@ -1175,7 +1175,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M66.BTMinerM66VL20
|
||||
@@ -1188,7 +1188,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M66.BTMinerM66VL30
|
||||
@@ -1201,7 +1201,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M6X.M67S.BTMinerM67SVK30
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
- [x] Shutdowns
|
||||
- [x] Power Modes
|
||||
- [x] Setpoints
|
||||
- [ ] Setpoints
|
||||
- [ ] Presets
|
||||
|
||||
::: pyasic.miners.whatsminer.btminer.M7X.M70.BTMinerM70VM30
|
||||
|
||||
@@ -97,6 +97,8 @@ nav:
|
||||
- Innosilicon T3X: "miners/innosilicon/T3X.md"
|
||||
- Innosilicon A10X: "miners/innosilicon/A10X.md"
|
||||
- Innosilicon A11X: "miners/innosilicon/A11X.md"
|
||||
- Goldshell Byte: "miners/goldshell/Byte.md"
|
||||
- Goldshell Mini Doge: "miners/goldshell/MiniDoge.md"
|
||||
- Goldshell X5: "miners/goldshell/X5.md"
|
||||
- Goldshell XMax: "miners/goldshell/XMax.md"
|
||||
- Goldshell XBox: "miners/goldshell/XBox.md"
|
||||
|
||||
14
poetry.lock
generated
14
poetry.lock
generated
@@ -1489,6 +1489,18 @@ urllib3 = ">=1.21.1,<3"
|
||||
socks = ["PySocks (>=1.5.6,!=1.5.7)"]
|
||||
use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "3.0.4"
|
||||
description = "Python helper for Semantic Versioning (https://semver.org)"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "semver-3.0.4-py3-none-any.whl", hash = "sha256:9c824d87ba7f7ab4a1890799cec8596f15c1241cb473404ea1cb0c55e4b04746"},
|
||||
{file = "semver-3.0.4.tar.gz", hash = "sha256:afc7d8c584a5ed0a11033af086e8af226a9c0b206f313e0301f8dd7b6b589602"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "six"
|
||||
version = "1.17.0"
|
||||
@@ -1702,4 +1714,4 @@ type = ["pytest-mypy"]
|
||||
[metadata]
|
||||
lock-version = "2.1"
|
||||
python-versions = ">3.9, <4.0"
|
||||
content-hash = "4152b0f7a2143d20368ddfad0aa44dfebdced4ab03586158a54eb27341a547e1"
|
||||
content-hash = "81ec4faceddb41badda1649e77ddcfba03b0275021ba37ba69290b7e6a326829"
|
||||
|
||||
@@ -85,6 +85,13 @@ class MinerConfig(BaseModel):
|
||||
**self.temperature.as_wm(),
|
||||
}
|
||||
|
||||
def as_btminer_v3(self, user_suffix: str | None = None) -> dict:
|
||||
"""Generates the configuration in the format suitable for Whatsminers running BTMiner V3."""
|
||||
return {
|
||||
"set.miner.pools": self.pools.as_btminer_v3()
|
||||
** self.mining_mode.as_btminer_v3()
|
||||
}
|
||||
|
||||
def as_am_old(self, user_suffix: str | None = None) -> dict:
|
||||
"""Generates the configuration in the format suitable for old versions of Antminers."""
|
||||
return {
|
||||
@@ -247,6 +254,16 @@ class MinerConfig(BaseModel):
|
||||
"""Constructs a MinerConfig object from web configuration for Goldshell miners."""
|
||||
return cls(pools=PoolConfig.from_am_modern(web_conf))
|
||||
|
||||
@classmethod
|
||||
def from_goldshell_list(cls, web_conf: list) -> "MinerConfig":
|
||||
"""Constructs a MinerConfig object from web configuration for Goldshell miners."""
|
||||
return cls(pools=PoolConfig.from_goldshell(web_conf))
|
||||
|
||||
@classmethod
|
||||
def from_goldshell_byte(cls, web_conf: dict) -> "MinerConfig":
|
||||
"""Constructs a MinerConfig object from web configuration for Goldshell Byte miners."""
|
||||
return cls(pools=PoolConfig.from_goldshell_byte(web_conf))
|
||||
|
||||
@classmethod
|
||||
def from_inno(cls, web_pools: list) -> "MinerConfig":
|
||||
"""Constructs a MinerConfig object from web configuration for Innosilicon miners."""
|
||||
@@ -350,3 +367,14 @@ class MinerConfig(BaseModel):
|
||||
@classmethod
|
||||
def from_hammer(cls, *args, **kwargs) -> "MinerConfig":
|
||||
return cls.from_am_modern(*args, **kwargs)
|
||||
|
||||
@classmethod
|
||||
def from_btminer_v3(
|
||||
cls, rpc_pools: dict, rpc_settings: dict, rpc_device_info: dict
|
||||
) -> "MinerConfig":
|
||||
return cls(
|
||||
pools=PoolConfig.from_btminer_v3(rpc_pools=rpc_pools["msg"]),
|
||||
mining_mode=MiningModeConfig.from_btminer_v3(
|
||||
rpc_device_info=rpc_device_info, rpc_settings=rpc_settings
|
||||
),
|
||||
)
|
||||
|
||||
@@ -107,6 +107,9 @@ class MinerConfigValue(BaseModel):
|
||||
def as_wm(self) -> dict:
|
||||
return {}
|
||||
|
||||
def as_btminer_v3(self) -> dict:
|
||||
return {}
|
||||
|
||||
def as_inno(self) -> dict:
|
||||
return {}
|
||||
|
||||
|
||||
@@ -63,6 +63,9 @@ class MiningModeNormal(MinerConfigValue):
|
||||
def as_wm(self) -> dict:
|
||||
return {"mode": self.mode}
|
||||
|
||||
def as_btminer_v3(self) -> dict:
|
||||
return {"set.miner.service": "start", "set.miner.power_mode": self.mode}
|
||||
|
||||
def as_auradine(self) -> dict:
|
||||
return {"mode": {"mode": self.mode}}
|
||||
|
||||
@@ -109,6 +112,9 @@ class MiningModeSleep(MinerConfigValue):
|
||||
def as_wm(self) -> dict:
|
||||
return {"mode": self.mode}
|
||||
|
||||
def as_btminer_v3(self) -> dict:
|
||||
return {"set.miner.service": "stop"}
|
||||
|
||||
def as_auradine(self) -> dict:
|
||||
return {"mode": {"sleep": "on"}}
|
||||
|
||||
@@ -149,6 +155,9 @@ class MiningModeLPM(MinerConfigValue):
|
||||
def as_wm(self) -> dict:
|
||||
return {"mode": self.mode}
|
||||
|
||||
def as_btminer_v3(self) -> dict:
|
||||
return {"set.miner.service": "start", "set.miner.power_mode": self.mode}
|
||||
|
||||
def as_auradine(self) -> dict:
|
||||
return {"mode": {"mode": "eco"}}
|
||||
|
||||
@@ -179,6 +188,9 @@ class MiningModeHPM(MinerConfigValue):
|
||||
def as_wm(self) -> dict:
|
||||
return {"mode": self.mode}
|
||||
|
||||
def as_btminer_v3(self) -> dict:
|
||||
return {"set.miner.service": "start", "set.miner.power_mode": self.mode}
|
||||
|
||||
def as_auradine(self) -> dict:
|
||||
return {"mode": {"mode": "turbo"}}
|
||||
|
||||
@@ -222,6 +234,9 @@ class MiningModePowerTune(MinerConfigValue):
|
||||
return {"mode": self.mode, self.mode: {"wattage": self.power}}
|
||||
return {}
|
||||
|
||||
def as_btminer_v3(self) -> dict:
|
||||
return {"set.miner.service": "start", "set.miner.power_limit": self.power}
|
||||
|
||||
def as_bosminer(self) -> dict:
|
||||
tuning_cfg = {"enabled": True, "mode": "power_target"}
|
||||
if self.power is not None:
|
||||
@@ -789,6 +804,26 @@ class MiningModeConfig(MinerConfigOption):
|
||||
except LookupError:
|
||||
return cls.default()
|
||||
|
||||
@classmethod
|
||||
def from_btminer_v3(cls, rpc_device_info: dict, rpc_settings: dict):
|
||||
try:
|
||||
is_mining = rpc_device_info["msg"]["miner"]["working"] == "true"
|
||||
if not is_mining:
|
||||
return cls.sleep()
|
||||
power_limit = rpc_settings["msg"]["power-limit"]
|
||||
if not power_limit == 0:
|
||||
return cls.power_tuning(power=power_limit)
|
||||
power_mode = rpc_settings["msg"]["power-mode"]
|
||||
if power_mode == "normal":
|
||||
return cls.normal()
|
||||
if power_mode == "high":
|
||||
return cls.high()
|
||||
if power_mode == "low":
|
||||
return cls.low()
|
||||
|
||||
except LookupError:
|
||||
return cls.default()
|
||||
|
||||
@classmethod
|
||||
def from_mara(cls, web_config: dict):
|
||||
try:
|
||||
|
||||
@@ -64,6 +64,13 @@ class Pool(MinerConfigValue):
|
||||
f"passwd_{idx}": self.password,
|
||||
}
|
||||
|
||||
def as_btminer_v3(self, user_suffix: str | None = None) -> dict:
|
||||
return {
|
||||
f"pool": self.url,
|
||||
f"worker": f"{self.user}{user_suffix or ''}",
|
||||
f"passwd": self.password,
|
||||
}
|
||||
|
||||
def as_am_old(self, idx: int = 1, user_suffix: str | None = None) -> dict:
|
||||
return {
|
||||
f"_ant_pool{idx}url": self.url,
|
||||
@@ -148,6 +155,10 @@ class Pool(MinerConfigValue):
|
||||
def from_api(cls, api_pool: dict) -> "Pool":
|
||||
return cls(url=api_pool["URL"], user=api_pool["User"], password="x")
|
||||
|
||||
@classmethod
|
||||
def from_btminer_v3(cls, api_pool: dict) -> "Pool":
|
||||
return cls(url=api_pool["url"], user=api_pool["account"], password="x")
|
||||
|
||||
@classmethod
|
||||
def from_epic(cls, api_pool: dict) -> "Pool":
|
||||
return cls(
|
||||
@@ -296,6 +307,9 @@ class PoolGroup(MinerConfigValue):
|
||||
idx += 1
|
||||
return pools
|
||||
|
||||
def as_btminer_v3(self, user_suffix: str | None = None) -> list:
|
||||
return [pool.as_btminer_v3(user_suffix) for pool in self.pools[:3]]
|
||||
|
||||
def as_am_old(self, user_suffix: str | None = None) -> dict:
|
||||
pools = {}
|
||||
idx = 0
|
||||
@@ -385,6 +399,13 @@ class PoolGroup(MinerConfigValue):
|
||||
pools.append(Pool.from_api(pool))
|
||||
return cls(pools=pools)
|
||||
|
||||
@classmethod
|
||||
def from_btminer_v3(cls, api_pool_list: list) -> "PoolGroup":
|
||||
pools = []
|
||||
for pool in api_pool_list:
|
||||
pools.append(Pool.from_btminer_v3(pool))
|
||||
return cls(pools=pools)
|
||||
|
||||
@classmethod
|
||||
def from_epic(cls, api_pool_list: list) -> "PoolGroup":
|
||||
pools = []
|
||||
@@ -513,6 +534,11 @@ class PoolConfig(MinerConfigValue):
|
||||
return {"pools": self.groups[0].as_wm(user_suffix=user_suffix)}
|
||||
return {"pools": PoolGroup().as_wm()}
|
||||
|
||||
def as_btminer_v3(self, user_suffix: str | None = None) -> dict:
|
||||
if len(self.groups) > 0:
|
||||
return {"pools": self.groups[0].as_btminer_v3(user_suffix=user_suffix)}
|
||||
return {"pools": PoolGroup().as_btminer_v3()}
|
||||
|
||||
def as_am_old(self, user_suffix: str | None = None) -> dict:
|
||||
if len(self.groups) > 0:
|
||||
return self.groups[0].as_am_old(user_suffix=user_suffix)
|
||||
@@ -598,6 +624,16 @@ class PoolConfig(MinerConfigValue):
|
||||
|
||||
return cls(groups=[PoolGroup.from_api(pool_data)])
|
||||
|
||||
@classmethod
|
||||
def from_btminer_v3(cls, rpc_pools: dict) -> "PoolConfig":
|
||||
try:
|
||||
pool_data = rpc_pools["pools"]
|
||||
except KeyError:
|
||||
return PoolConfig.default()
|
||||
pool_data = sorted(pool_data, key=lambda x: int(x["id"]))
|
||||
|
||||
return cls(groups=[PoolGroup.from_btminer_v3(pool_data)])
|
||||
|
||||
@classmethod
|
||||
def from_epic(cls, web_conf: dict) -> "PoolConfig":
|
||||
pool_data = web_conf["StratumConfigs"]
|
||||
@@ -631,6 +667,16 @@ class PoolConfig(MinerConfigValue):
|
||||
def from_goldshell(cls, web_pools: list) -> "PoolConfig":
|
||||
return cls(groups=[PoolGroup.from_goldshell(web_pools)])
|
||||
|
||||
@classmethod
|
||||
def from_goldshell_byte(cls, web_pools: list) -> "PoolConfig":
|
||||
return cls(
|
||||
groups=[
|
||||
PoolGroup.from_goldshell(g["pools"])
|
||||
for g in web_pools
|
||||
if len(g["pools"]) > 0
|
||||
]
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_inno(cls, web_pools: list) -> "PoolConfig":
|
||||
return cls(groups=[PoolGroup.from_inno(web_pools)])
|
||||
|
||||
@@ -77,7 +77,6 @@ class HashBoard(BaseModel):
|
||||
raise KeyError(f"{item}")
|
||||
|
||||
def as_influxdb(self, key_root: str, level_delimiter: str = ".") -> str:
|
||||
|
||||
def serialize_int(key: str, value: int) -> str:
|
||||
return f"{key}={value}"
|
||||
|
||||
|
||||
@@ -94,7 +94,6 @@ class PoolMetrics(BaseModel):
|
||||
return (value / total) * 100
|
||||
|
||||
def as_influxdb(self, key_root: str, level_delimiter: str = ".") -> str:
|
||||
|
||||
def serialize_int(key: str, value: int) -> str:
|
||||
return f"{key}={value}"
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ from .kheavyhash import KHeavyHashAlgo
|
||||
from .scrypt import ScryptAlgo
|
||||
from .sha256 import SHA256Algo
|
||||
from .x11 import X11Algo
|
||||
from .zksnark import ZkSnarkAlgo
|
||||
|
||||
|
||||
class MinerAlgo:
|
||||
@@ -26,3 +27,4 @@ class MinerAlgo:
|
||||
ETHASH = EtHashAlgo
|
||||
EQUIHASH = EquihashAlgo
|
||||
BLOCKFLOW = BlockFlowAlgo
|
||||
ZKSNARK = ZkSnarkAlgo
|
||||
|
||||
@@ -10,6 +10,7 @@ from .kheavyhash import KHeavyHashHashRate
|
||||
from .scrypt import ScryptHashRate
|
||||
from .sha256 import SHA256HashRate
|
||||
from .x11 import X11HashRate
|
||||
from .zksnark import ZkSnarkHashRate
|
||||
|
||||
|
||||
class AlgoHashRate:
|
||||
@@ -24,3 +25,4 @@ class AlgoHashRate:
|
||||
ETHASH = EtHashHashRate
|
||||
EQUIHASH = EquihashHashRate
|
||||
BLOCKFLOW = BlockFlowHashRate
|
||||
ZKSNARK = ZkSnarkHashRate
|
||||
|
||||
@@ -9,6 +9,7 @@ from .kheavyhash import KHeavyHashUnit
|
||||
from .scrypt import ScryptUnit
|
||||
from .sha256 import SHA256Unit
|
||||
from .x11 import X11Unit
|
||||
from .zksnark import ZkSnarkUnit
|
||||
|
||||
|
||||
class HashUnit:
|
||||
@@ -23,3 +24,4 @@ class HashUnit:
|
||||
ETHASH = EtHashUnit
|
||||
EQUIHASH = EquihashUnit
|
||||
BLOCKFLOW = BlockFlowUnit
|
||||
ZKSNARK = ZkSnarkUnit
|
||||
|
||||
16
pyasic/device/algorithm/hashrate/unit/zksnark.py
Normal file
16
pyasic/device/algorithm/hashrate/unit/zksnark.py
Normal file
@@ -0,0 +1,16 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from .base import AlgoHashRateUnitType
|
||||
|
||||
|
||||
class ZkSnarkUnit(AlgoHashRateUnitType):
|
||||
H = 1
|
||||
KH = int(H) * 1000
|
||||
MH = int(KH) * 1000
|
||||
GH = int(MH) * 1000
|
||||
TH = int(GH) * 1000
|
||||
PH = int(TH) * 1000
|
||||
EH = int(PH) * 1000
|
||||
ZH = int(EH) * 1000
|
||||
|
||||
default = GH
|
||||
18
pyasic/device/algorithm/hashrate/zksnark.py
Normal file
18
pyasic/device/algorithm/hashrate/zksnark.py
Normal file
@@ -0,0 +1,18 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing_extensions import Self
|
||||
|
||||
from pyasic.device.algorithm.hashrate.base import AlgoHashRateType
|
||||
from pyasic.device.algorithm.hashrate.unit.zksnark import ZkSnarkUnit
|
||||
|
||||
from .unit import HashUnit
|
||||
|
||||
|
||||
class ZkSnarkHashRate(AlgoHashRateType):
|
||||
rate: float
|
||||
unit: ZkSnarkUnit = HashUnit.ZKSNARK.default
|
||||
|
||||
def into(self, other: ZkSnarkUnit) -> Self:
|
||||
return self.__class__(
|
||||
rate=self.rate / (other.value / self.unit.value), unit=other
|
||||
)
|
||||
12
pyasic/device/algorithm/zksnark.py
Normal file
12
pyasic/device/algorithm/zksnark.py
Normal file
@@ -0,0 +1,12 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from .base import MinerAlgoType
|
||||
from .hashrate import ZkSnarkHashRate
|
||||
from .hashrate.unit import ZkSnarkUnit
|
||||
|
||||
|
||||
class ZkSnarkAlgo(MinerAlgoType):
|
||||
hashrate: type[ZkSnarkHashRate] = ZkSnarkHashRate
|
||||
unit: type[ZkSnarkUnit] = ZkSnarkUnit
|
||||
|
||||
name = "zkSNARK"
|
||||
@@ -479,6 +479,8 @@ class GoldshellModels(MinerModelType):
|
||||
KDMax = "KD Max"
|
||||
KDBoxII = "KD Box II"
|
||||
KDBoxPro = "KD Box Pro"
|
||||
Byte = "Byte"
|
||||
MiniDoge = "Mini Doge"
|
||||
|
||||
def __str__(self):
|
||||
return self.value
|
||||
|
||||
@@ -167,7 +167,6 @@ class CGMinerAvalonNano3(AvalonMiner, AvalonNano3):
|
||||
|
||||
|
||||
class CGMinerAvalonNano3s(AvalonMiner, AvalonNano3s):
|
||||
|
||||
data_locations = AVALON_NANO3S_DATA_LOC
|
||||
|
||||
async def _get_wattage(self, rpc_estats: dict = None) -> Optional[int]:
|
||||
@@ -179,8 +178,7 @@ class CGMinerAvalonNano3s(AvalonMiner, AvalonNano3s):
|
||||
|
||||
if rpc_estats is not None:
|
||||
try:
|
||||
unparsed_estats = rpc_estats["STATS"][0]["MM ID0"]
|
||||
parsed_estats = self.parse_estats(unparsed_estats)
|
||||
parsed_estats = self.parse_estats(rpc_estats)["STATS"][0]["MM ID0"]
|
||||
return int(parsed_estats["PS"][6])
|
||||
except (IndexError, KeyError, ValueError, TypeError):
|
||||
pass
|
||||
@@ -194,8 +192,7 @@ class CGMinerAvalonNano3s(AvalonMiner, AvalonNano3s):
|
||||
|
||||
if rpc_estats is not None:
|
||||
try:
|
||||
unparsed_estats = rpc_estats["STATS"][0]["MM ID0"]
|
||||
parsed_estats = self.parse_estats(unparsed_estats)
|
||||
parsed_estats = self.parse_estats(rpc_estats)["STATS"][0]["MM ID0"]
|
||||
return self.algo.hashrate(
|
||||
rate=float(parsed_estats["GHSspd"]), unit=self.algo.unit.GH
|
||||
).into(self.algo.unit.default)
|
||||
@@ -212,16 +209,14 @@ class CGMinerAvalonNano3s(AvalonMiner, AvalonNano3s):
|
||||
pass
|
||||
|
||||
if rpc_estats is not None:
|
||||
|
||||
try:
|
||||
unparsed_estats = rpc_estats["STATS"][0]["MM ID0"]
|
||||
parsed_estats = self.parse_estats(unparsed_estats)
|
||||
parsed_estats = self.parse_estats(rpc_estats)["STATS"][0]["MM ID0"]
|
||||
except (IndexError, KeyError, ValueError, TypeError):
|
||||
return hashboards
|
||||
|
||||
for board in range(len(hashboards)):
|
||||
try:
|
||||
board_hr = parsed_estats["GHSspd"][board]
|
||||
board_hr = parsed_estats["GHSspd"]
|
||||
hashboards[board].hashrate = self.algo.hashrate(
|
||||
rate=float(board_hr), unit=self.algo.unit.GH
|
||||
).into(self.algo.unit.default)
|
||||
|
||||
@@ -20,7 +20,7 @@ from .bfgminer import BFGMiner
|
||||
from .bitaxe import BitAxe
|
||||
from .bmminer import BMMiner
|
||||
from .braiins_os import BOSer, BOSMiner
|
||||
from .btminer import BTMiner
|
||||
from .btminer import BTMiner, BTMinerV2, BTMinerV3
|
||||
from .cgminer import CGMiner
|
||||
from .elphapex import ElphapexMiner
|
||||
from .epic import ePIC
|
||||
|
||||
@@ -287,7 +287,6 @@ class AvalonMiner(CGMiner):
|
||||
return hashboards
|
||||
|
||||
for board in range(self.expected_hashboards):
|
||||
|
||||
try:
|
||||
board_hr = parsed_estats["STATS"][0]["MM ID0"]["MGHS"]
|
||||
if isinstance(board_hr, list):
|
||||
@@ -306,10 +305,12 @@ class AvalonMiner(CGMiner):
|
||||
hashboards[board].chip_temp = int(
|
||||
parsed_estats["STATS"][0]["MM ID0"]["MTmax"][board]
|
||||
)
|
||||
except LookupError:
|
||||
except (LookupError, TypeError):
|
||||
try:
|
||||
hashboards[board].chip_temp = int(
|
||||
parsed_estats["STATS"][0]["MM ID0"]["Tmax"]
|
||||
parsed_estats["STATS"][0]["MM ID0"].get(
|
||||
"Tmax", parsed_estats["STATS"][0]["MM ID0"]["TMax"]
|
||||
)
|
||||
)
|
||||
except LookupError:
|
||||
pass
|
||||
@@ -318,10 +319,12 @@ class AvalonMiner(CGMiner):
|
||||
hashboards[board].temp = int(
|
||||
parsed_estats["STATS"][0]["MM ID0"]["MTmax"][board]
|
||||
)
|
||||
except LookupError:
|
||||
except (LookupError, TypeError):
|
||||
try:
|
||||
hashboards[board].temp = int(
|
||||
parsed_estats["STATS"][0]["MM ID0"]["Tavg"]
|
||||
parsed_estats["STATS"][0]["MM ID0"].get(
|
||||
"Tavg", parsed_estats["STATS"][0]["MM ID0"]["TAvg"]
|
||||
)
|
||||
)
|
||||
except LookupError:
|
||||
pass
|
||||
@@ -330,7 +333,7 @@ class AvalonMiner(CGMiner):
|
||||
hashboards[board].inlet_temp = int(
|
||||
parsed_estats["STATS"][0]["MM ID0"]["MTavg"][board]
|
||||
)
|
||||
except LookupError:
|
||||
except (LookupError, TypeError):
|
||||
try:
|
||||
hashboards[board].inlet_temp = int(
|
||||
parsed_estats["STATS"][0]["MM ID0"]["HBITemp"]
|
||||
@@ -342,7 +345,7 @@ class AvalonMiner(CGMiner):
|
||||
hashboards[board].outlet_temp = int(
|
||||
parsed_estats["STATS"][0]["MM ID0"]["MTmax"][board]
|
||||
)
|
||||
except LookupError:
|
||||
except (LookupError, TypeError):
|
||||
try:
|
||||
hashboards[board].outlet_temp = int(
|
||||
parsed_estats["STATS"][0]["MM ID0"]["HBOTemp"]
|
||||
@@ -357,7 +360,7 @@ class AvalonMiner(CGMiner):
|
||||
hashboards[board].chips = len(
|
||||
[item for item in chip_data if not item == "0"]
|
||||
)
|
||||
except LookupError:
|
||||
except (LookupError, TypeError):
|
||||
try:
|
||||
chip_data = parsed_estats["STATS"][0]["HBinfo"][f"HB{board}"][
|
||||
f"PVT_T{board}"
|
||||
|
||||
@@ -216,7 +216,7 @@ class BFGMiner(StockFirmware):
|
||||
)
|
||||
except LookupError:
|
||||
pass
|
||||
fans = [Fan(speed=d) if d else Fan() for d in fans_data]
|
||||
fans = [Fan(speed=d) for d in fans_data if d is not None]
|
||||
|
||||
return fans
|
||||
|
||||
|
||||
@@ -13,14 +13,14 @@
|
||||
# See the License for the specific language governing permissions and -
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
from pathlib import Path
|
||||
from typing import List, Optional
|
||||
|
||||
import aiofiles
|
||||
import semver
|
||||
|
||||
from pyasic.config import MinerConfig, MiningModeConfig
|
||||
from pyasic.config import MinerConfig, MiningModeConfig, PoolConfig
|
||||
from pyasic.data import Fan, HashBoard
|
||||
from pyasic.data.error_codes import MinerErrorData, WhatsminerError
|
||||
from pyasic.data.pools import PoolMetrics, PoolUrl
|
||||
@@ -28,7 +28,36 @@ from pyasic.device.algorithm import AlgoHashRate
|
||||
from pyasic.errors import APIError
|
||||
from pyasic.miners.data import DataFunction, DataLocations, DataOptions, RPCAPICommand
|
||||
from pyasic.miners.device.firmware import StockFirmware
|
||||
from pyasic.rpc.btminer import BTMinerRPCAPI
|
||||
from pyasic.rpc.btminer import BTMinerRPCAPI, BTMinerV3RPCAPI
|
||||
|
||||
|
||||
class BTMiner(StockFirmware):
|
||||
def __new__(cls, ip: str, version: str | None = None):
|
||||
bases = cls.__bases__
|
||||
bases = bases[1:]
|
||||
|
||||
def get_new(v: str | None):
|
||||
if v is None:
|
||||
return BTMinerV2
|
||||
try:
|
||||
semantic = semver.Version(
|
||||
major=int(v[0:4]),
|
||||
minor=int(v[4:6]),
|
||||
patch=int(v[6:8]),
|
||||
)
|
||||
except ValueError:
|
||||
return BTMinerV2
|
||||
if semantic > semver.Version(major=2024, minor=11, patch=0):
|
||||
return BTMinerV3
|
||||
return BTMinerV2
|
||||
|
||||
inject = get_new(version)
|
||||
|
||||
bases = (inject,) + bases
|
||||
|
||||
cls = type(cls.__name__, bases, {})(ip=ip, version=version)
|
||||
return cls
|
||||
|
||||
|
||||
BTMINER_DATA_LOC = DataLocations(
|
||||
**{
|
||||
@@ -119,7 +148,7 @@ BTMINER_DATA_LOC = DataLocations(
|
||||
)
|
||||
|
||||
|
||||
class BTMiner(StockFirmware):
|
||||
class BTMinerV2(StockFirmware):
|
||||
"""Base handler for BTMiner based miners."""
|
||||
|
||||
_rpc_cls = BTMinerRPCAPI
|
||||
@@ -294,7 +323,7 @@ class BTMiner(StockFirmware):
|
||||
|
||||
async def _get_mac(
|
||||
self, rpc_summary: dict = None, rpc_get_miner_info: dict = None
|
||||
) -> Optional[str]:
|
||||
) -> str | None:
|
||||
if rpc_get_miner_info is None:
|
||||
try:
|
||||
rpc_get_miner_info = await self.rpc.get_miner_info()
|
||||
@@ -321,7 +350,7 @@ class BTMiner(StockFirmware):
|
||||
except LookupError:
|
||||
pass
|
||||
|
||||
async def _get_api_ver(self, rpc_get_version: dict = None) -> Optional[str]:
|
||||
async def _get_api_ver(self, rpc_get_version: dict = None) -> str | None:
|
||||
if rpc_get_version is None:
|
||||
try:
|
||||
rpc_get_version = await self.rpc.get_version()
|
||||
@@ -346,7 +375,7 @@ class BTMiner(StockFirmware):
|
||||
|
||||
async def _get_fw_ver(
|
||||
self, rpc_get_version: dict = None, rpc_summary: dict = None
|
||||
) -> Optional[str]:
|
||||
) -> str | None:
|
||||
if rpc_get_version is None:
|
||||
try:
|
||||
rpc_get_version = await self.rpc.get_version()
|
||||
@@ -379,7 +408,7 @@ class BTMiner(StockFirmware):
|
||||
|
||||
return self.fw_ver
|
||||
|
||||
async def _get_hostname(self, rpc_get_miner_info: dict = None) -> Optional[str]:
|
||||
async def _get_hostname(self, rpc_get_miner_info: dict = None) -> str | None:
|
||||
hostname = None
|
||||
if rpc_get_miner_info is None:
|
||||
try:
|
||||
@@ -395,7 +424,7 @@ class BTMiner(StockFirmware):
|
||||
|
||||
return hostname
|
||||
|
||||
async def _get_hashrate(self, rpc_summary: dict = None) -> Optional[AlgoHashRate]:
|
||||
async def _get_hashrate(self, rpc_summary: dict = None) -> AlgoHashRate | None:
|
||||
if rpc_summary is None:
|
||||
try:
|
||||
rpc_summary = await self.rpc.summary()
|
||||
@@ -410,8 +439,9 @@ class BTMiner(StockFirmware):
|
||||
).into(self.algo.unit.default)
|
||||
except LookupError:
|
||||
pass
|
||||
return None
|
||||
|
||||
async def _get_hashboards(self, rpc_devs: dict = None) -> List[HashBoard]:
|
||||
async def _get_hashboards(self, rpc_devs: dict = None) -> list[HashBoard]:
|
||||
if self.expected_hashboards is None:
|
||||
return []
|
||||
|
||||
@@ -450,7 +480,7 @@ class BTMiner(StockFirmware):
|
||||
|
||||
return hashboards
|
||||
|
||||
async def _get_env_temp(self, rpc_summary: dict = None) -> Optional[float]:
|
||||
async def _get_env_temp(self, rpc_summary: dict = None) -> float | None:
|
||||
if rpc_summary is None:
|
||||
try:
|
||||
rpc_summary = await self.rpc.summary()
|
||||
@@ -462,8 +492,9 @@ class BTMiner(StockFirmware):
|
||||
return rpc_summary["SUMMARY"][0]["Env Temp"]
|
||||
except LookupError:
|
||||
pass
|
||||
return None
|
||||
|
||||
async def _get_wattage(self, rpc_summary: dict = None) -> Optional[int]:
|
||||
async def _get_wattage(self, rpc_summary: dict = None) -> int | None:
|
||||
if rpc_summary is None:
|
||||
try:
|
||||
rpc_summary = await self.rpc.summary()
|
||||
@@ -476,8 +507,9 @@ class BTMiner(StockFirmware):
|
||||
return wattage if not wattage == -1 else None
|
||||
except LookupError:
|
||||
pass
|
||||
return None
|
||||
|
||||
async def _get_wattage_limit(self, rpc_summary: dict = None) -> Optional[int]:
|
||||
async def _get_wattage_limit(self, rpc_summary: dict = None) -> int | None:
|
||||
if rpc_summary is None:
|
||||
try:
|
||||
rpc_summary = await self.rpc.summary()
|
||||
@@ -489,10 +521,11 @@ class BTMiner(StockFirmware):
|
||||
return rpc_summary["SUMMARY"][0]["Power Limit"]
|
||||
except LookupError:
|
||||
pass
|
||||
return None
|
||||
|
||||
async def _get_fans(
|
||||
self, rpc_summary: dict = None, rpc_get_psu: dict = None
|
||||
) -> List[Fan]:
|
||||
) -> list[Fan]:
|
||||
if self.expected_fans is None:
|
||||
return []
|
||||
|
||||
@@ -517,7 +550,7 @@ class BTMiner(StockFirmware):
|
||||
|
||||
async def _get_fan_psu(
|
||||
self, rpc_summary: dict = None, rpc_get_psu: dict = None
|
||||
) -> Optional[int]:
|
||||
) -> int | None:
|
||||
if rpc_summary is None:
|
||||
try:
|
||||
rpc_summary = await self.rpc.summary()
|
||||
@@ -541,10 +574,11 @@ class BTMiner(StockFirmware):
|
||||
return int(rpc_get_psu["Msg"]["fan_speed"])
|
||||
except (KeyError, TypeError):
|
||||
pass
|
||||
return None
|
||||
|
||||
async def _get_errors(
|
||||
self, rpc_summary: dict = None, rpc_get_error_code: dict = None
|
||||
) -> List[MinerErrorData]:
|
||||
) -> list[MinerErrorData]:
|
||||
errors = []
|
||||
if rpc_get_error_code is None and rpc_summary is None:
|
||||
try:
|
||||
@@ -581,7 +615,7 @@ class BTMiner(StockFirmware):
|
||||
|
||||
async def _get_expected_hashrate(
|
||||
self, rpc_summary: dict = None
|
||||
) -> Optional[AlgoHashRate]:
|
||||
) -> AlgoHashRate | None:
|
||||
if rpc_summary is None:
|
||||
try:
|
||||
rpc_summary = await self.rpc.summary()
|
||||
@@ -598,8 +632,9 @@ class BTMiner(StockFirmware):
|
||||
|
||||
except LookupError:
|
||||
pass
|
||||
return None
|
||||
|
||||
async def _get_fault_light(self, rpc_get_miner_info: dict = None) -> Optional[bool]:
|
||||
async def _get_fault_light(self, rpc_get_miner_info: dict = None) -> bool | None:
|
||||
if rpc_get_miner_info is None:
|
||||
try:
|
||||
rpc_get_miner_info = await self.rpc.get_miner_info()
|
||||
@@ -637,7 +672,7 @@ class BTMiner(StockFirmware):
|
||||
async def set_hostname(self, hostname: str):
|
||||
await self.rpc.set_hostname(hostname)
|
||||
|
||||
async def _is_mining(self, rpc_status: dict = None) -> Optional[bool]:
|
||||
async def _is_mining(self, rpc_status: dict = None) -> bool | None:
|
||||
if rpc_status is None:
|
||||
try:
|
||||
rpc_status = await self.rpc.status()
|
||||
@@ -655,8 +690,9 @@ class BTMiner(StockFirmware):
|
||||
return True if rpc_status["Msg"]["mineroff"] == "false" else False
|
||||
except LookupError:
|
||||
pass
|
||||
return False
|
||||
|
||||
async def _get_uptime(self, rpc_summary: dict = None) -> Optional[int]:
|
||||
async def _get_uptime(self, rpc_summary: dict = None) -> int | None:
|
||||
if rpc_summary is None:
|
||||
try:
|
||||
rpc_summary = await self.rpc.summary()
|
||||
@@ -669,7 +705,7 @@ class BTMiner(StockFirmware):
|
||||
except LookupError:
|
||||
pass
|
||||
|
||||
async def _get_pools(self, rpc_pools: dict = None) -> List[PoolMetrics]:
|
||||
async def _get_pools(self, rpc_pools: dict = None) -> list[PoolMetrics]:
|
||||
if rpc_pools is None:
|
||||
try:
|
||||
rpc_pools = await self.rpc.pools()
|
||||
@@ -742,3 +778,414 @@ class BTMiner(StockFirmware):
|
||||
exc_info=True,
|
||||
)
|
||||
raise
|
||||
|
||||
|
||||
BTMINERV3_DATA_LOC = DataLocations(
|
||||
**{
|
||||
str(DataOptions.MAC): DataFunction(
|
||||
"_get_mac", [RPCAPICommand("rpc_get_device_info", "get.device.info")]
|
||||
),
|
||||
str(DataOptions.API_VERSION): DataFunction(
|
||||
"_get_api_version",
|
||||
[RPCAPICommand("rpc_get_device_info", "get.device.info")],
|
||||
),
|
||||
str(DataOptions.FW_VERSION): DataFunction(
|
||||
"_get_firmware_version",
|
||||
[RPCAPICommand("rpc_get_device_info", "get.device.info")],
|
||||
),
|
||||
str(DataOptions.HOSTNAME): DataFunction(
|
||||
"_get_hostname", [RPCAPICommand("rpc_get_device_info", "get.device.info")]
|
||||
),
|
||||
str(DataOptions.FAULT_LIGHT): DataFunction(
|
||||
"_get_light_flashing",
|
||||
[RPCAPICommand("rpc_get_device_info", "get.device.info")],
|
||||
),
|
||||
str(DataOptions.WATTAGE_LIMIT): DataFunction(
|
||||
"_get_wattage_limit",
|
||||
[RPCAPICommand("rpc_get_device_info", "get.device.info")],
|
||||
),
|
||||
str(DataOptions.FANS): DataFunction(
|
||||
"_get_fans",
|
||||
[RPCAPICommand("rpc_get_miner_status_summary", "get.miner.status:summary")],
|
||||
),
|
||||
str(DataOptions.FAN_PSU): DataFunction(
|
||||
"_get_psu_fans", [RPCAPICommand("rpc_get_device_info", "get.device.info")]
|
||||
),
|
||||
str(DataOptions.HASHBOARDS): DataFunction(
|
||||
"_get_hashboards",
|
||||
[
|
||||
RPCAPICommand("rpc_get_device_info", "get.device.info"),
|
||||
RPCAPICommand(
|
||||
"rpc_get_miner_status_edevs",
|
||||
"get.miner.status:edevs",
|
||||
),
|
||||
],
|
||||
),
|
||||
str(DataOptions.POOLS): DataFunction(
|
||||
"_get_pools",
|
||||
[RPCAPICommand("rpc_get_miner_status_summary", "get.miner.status:summary")],
|
||||
),
|
||||
str(DataOptions.UPTIME): DataFunction(
|
||||
"_get_uptime",
|
||||
[RPCAPICommand("rpc_get_miner_status_summary", "get.miner.status:summary")],
|
||||
),
|
||||
str(DataOptions.WATTAGE): DataFunction(
|
||||
"_get_wattage",
|
||||
[RPCAPICommand("rpc_get_miner_status_summary", "get.miner.status:summary")],
|
||||
),
|
||||
str(DataOptions.HASHRATE): DataFunction(
|
||||
"_get_hashrate",
|
||||
[RPCAPICommand("rpc_get_miner_status_summary", "get.miner.status:summary")],
|
||||
),
|
||||
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
|
||||
"_get_expected_hashrate",
|
||||
[RPCAPICommand("rpc_get_miner_status_summary", "get.miner.status:summary")],
|
||||
),
|
||||
str(DataOptions.ENVIRONMENT_TEMP): DataFunction(
|
||||
"_get_env_temp",
|
||||
[RPCAPICommand("rpc_get_miner_status_summary", "get.miner.status:summary")],
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
class BTMinerV3(StockFirmware):
|
||||
_rpc_cls = BTMinerV3RPCAPI
|
||||
rpc: BTMinerV3RPCAPI
|
||||
|
||||
data_locations = BTMINERV3_DATA_LOC
|
||||
|
||||
supports_shutdown = True
|
||||
supports_autotuning = True
|
||||
supports_power_modes = True
|
||||
|
||||
async def get_config(self) -> MinerConfig:
|
||||
pools = None
|
||||
settings = None
|
||||
device_info = None
|
||||
try:
|
||||
pools = await self.rpc.get_miner_status_pools()
|
||||
settings = await self.rpc.get_miner_setting()
|
||||
device_info = await self.rpc.get_device_info()
|
||||
except APIError as e:
|
||||
logging.warning(e)
|
||||
except LookupError:
|
||||
pass
|
||||
|
||||
self.config = MinerConfig.from_btminer_v3(
|
||||
rpc_pools=pools, rpc_settings=settings, rpc_device_info=device_info
|
||||
)
|
||||
|
||||
return self.config
|
||||
|
||||
async def send_config(self, config: MinerConfig, user_suffix: str = None) -> None:
|
||||
self.config = config
|
||||
|
||||
conf = config.as_btminer_v3(user_suffix=user_suffix)
|
||||
|
||||
await asyncio.gather(
|
||||
*[self.rpc.send_command(k, parameters=v) for k, v in conf.values()]
|
||||
)
|
||||
|
||||
async def fault_light_off(self) -> bool:
|
||||
try:
|
||||
data = await self.rpc.set_system_led()
|
||||
except APIError:
|
||||
return False
|
||||
if data:
|
||||
if "code" in data.keys():
|
||||
if data["code"] == 0:
|
||||
self.light = False
|
||||
return True
|
||||
return False
|
||||
|
||||
async def fault_light_on(self) -> bool:
|
||||
try:
|
||||
data = await self.rpc.set_system_led(
|
||||
leds=[
|
||||
{
|
||||
{"color": "red", "period": 60, "duration": 20, "start": 0},
|
||||
}
|
||||
],
|
||||
)
|
||||
except APIError:
|
||||
return False
|
||||
if data:
|
||||
if "code" in data.keys():
|
||||
if data["code"] == 0:
|
||||
self.light = True
|
||||
return True
|
||||
return False
|
||||
|
||||
async def reboot(self) -> bool:
|
||||
try:
|
||||
data = await self.rpc.set_system_reboot()
|
||||
except APIError:
|
||||
return False
|
||||
if data.get("msg"):
|
||||
if data["msg"] == "ok":
|
||||
return True
|
||||
return False
|
||||
|
||||
async def restart_backend(self) -> bool:
|
||||
try:
|
||||
data = await self.rpc.set_miner_service("restart")
|
||||
except APIError:
|
||||
return False
|
||||
if data.get("msg"):
|
||||
if data["msg"] == "ok":
|
||||
return True
|
||||
return False
|
||||
|
||||
async def stop_mining(self) -> bool:
|
||||
try:
|
||||
data = await self.rpc.set_miner_service("stop")
|
||||
except APIError:
|
||||
return False
|
||||
if data.get("msg"):
|
||||
if data["msg"] == "ok":
|
||||
return True
|
||||
return False
|
||||
|
||||
async def resume_mining(self) -> bool:
|
||||
try:
|
||||
data = await self.rpc.set_miner_service("start")
|
||||
except APIError:
|
||||
return False
|
||||
if data.get("msg"):
|
||||
if data["msg"] == "ok":
|
||||
return True
|
||||
return False
|
||||
|
||||
async def set_power_limit(self, wattage: int) -> bool:
|
||||
try:
|
||||
await self.rpc.set_miner_power_limit(wattage)
|
||||
except Exception as e:
|
||||
logging.warning(f"{self} set_power_limit: {e}")
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
async def _get_mac(self, rpc_get_device_info: dict = None) -> str | None:
|
||||
if rpc_get_device_info is None:
|
||||
try:
|
||||
rpc_get_device_info = await self.rpc.get_device_info()
|
||||
except APIError:
|
||||
return None
|
||||
return rpc_get_device_info.get("msg", {}).get("network", {}).get("mac")
|
||||
|
||||
async def _get_api_version(self, rpc_get_device_info: dict = None) -> str | None:
|
||||
if rpc_get_device_info is None:
|
||||
try:
|
||||
rpc_get_device_info = await self.rpc.get_device_info()
|
||||
except APIError:
|
||||
return None
|
||||
return rpc_get_device_info.get("msg", {}).get("system", {}).get("api")
|
||||
|
||||
async def _get_firmware_version(
|
||||
self, rpc_get_device_info: dict = None
|
||||
) -> str | None:
|
||||
if rpc_get_device_info is None:
|
||||
try:
|
||||
rpc_get_device_info = await self.rpc.get_device_info()
|
||||
except APIError:
|
||||
return None
|
||||
return rpc_get_device_info.get("msg", {}).get("system", {}).get("fwversion")
|
||||
|
||||
async def _get_hostname(self, rpc_get_device_info: dict = None) -> str | None:
|
||||
if rpc_get_device_info is None:
|
||||
try:
|
||||
rpc_get_device_info = await self.rpc.get_device_info()
|
||||
except APIError:
|
||||
return None
|
||||
return rpc_get_device_info.get("msg", {}).get("network", {}).get("hostname")
|
||||
|
||||
async def _get_light_flashing(
|
||||
self, rpc_get_device_info: dict = None
|
||||
) -> bool | None:
|
||||
if rpc_get_device_info is None:
|
||||
try:
|
||||
rpc_get_device_info = await self.rpc.get_device_info()
|
||||
except APIError:
|
||||
return None
|
||||
val = rpc_get_device_info.get("msg", {}).get("system", {}).get("ledstatus")
|
||||
if isinstance(val, str):
|
||||
return val != "auto"
|
||||
return None
|
||||
|
||||
async def _get_wattage_limit(
|
||||
self, rpc_get_device_info: dict = None
|
||||
) -> float | None:
|
||||
if rpc_get_device_info is None:
|
||||
try:
|
||||
rpc_get_device_info = await self.rpc.get_device_info()
|
||||
except APIError:
|
||||
return None
|
||||
val = rpc_get_device_info.get("msg", {}).get("miner", {}).get("power-limit-set")
|
||||
try:
|
||||
return float(val)
|
||||
except (ValueError, TypeError):
|
||||
return None
|
||||
|
||||
async def _get_fans(self, rpc_get_miner_status_summary: dict = None) -> list[Fan]:
|
||||
if rpc_get_miner_status_summary is None:
|
||||
try:
|
||||
rpc_get_miner_status_summary = await self.rpc.get_miner_status_summary()
|
||||
except APIError:
|
||||
return []
|
||||
fans = []
|
||||
summary = rpc_get_miner_status_summary.get("msg", {}).get("summary", {})
|
||||
for idx, direction in enumerate(["in", "out"]):
|
||||
rpm = summary.get(f"fan-speed-{direction}")
|
||||
if rpm is not None:
|
||||
fans.append(Fan(speed=rpm))
|
||||
return fans
|
||||
|
||||
async def _get_psu_fans(self, rpc_get_device_info: dict = None) -> list[Fan]:
|
||||
if rpc_get_device_info is None:
|
||||
try:
|
||||
rpc_get_device_info = await self.rpc.get_device_info()
|
||||
except APIError:
|
||||
return []
|
||||
rpm = rpc_get_device_info.get("msg", {}).get("power", {}).get("fanspeed")
|
||||
return [Fan(speed=rpm)] if rpm is not None else []
|
||||
|
||||
async def _get_hashboards(
|
||||
self,
|
||||
rpc_get_device_info: dict = None,
|
||||
rpc_get_miner_status_edevs: dict = None,
|
||||
) -> list[HashBoard]:
|
||||
if rpc_get_device_info is None:
|
||||
try:
|
||||
rpc_get_device_info = await self.rpc.get_device_info()
|
||||
except APIError:
|
||||
return []
|
||||
if rpc_get_miner_status_edevs is None:
|
||||
try:
|
||||
rpc_get_miner_status_edevs = await self.rpc.get_miner_status_edevs()
|
||||
except APIError:
|
||||
return []
|
||||
|
||||
boards = []
|
||||
board_count = (
|
||||
rpc_get_device_info.get("msg", {}).get("hardware", {}).get("boards", 3)
|
||||
)
|
||||
edevs = rpc_get_miner_status_edevs.get("msg", {}).get("edevs", [])
|
||||
for idx in range(board_count):
|
||||
board_data = edevs[idx] if idx < len(edevs) else {}
|
||||
boards.append(
|
||||
HashBoard(
|
||||
slot=idx,
|
||||
hashrate=self.algo.hashrate(
|
||||
rate=board_data.get("hash-average", 0), unit=self.algo.unit.TH
|
||||
).into(self.algo.unit.default),
|
||||
temp=board_data.get("chip-temp-min"),
|
||||
inlet_temp=board_data.get("chip-temp-min"),
|
||||
outlet_temp=board_data.get("chip-temp-max"),
|
||||
serial_number=rpc_get_device_info.get("msg", {})
|
||||
.get("miner", {})
|
||||
.get(f"pcbsn{idx}"),
|
||||
chips=board_data.get("effective-chips"),
|
||||
expected_chips=self.expected_chips,
|
||||
active=(board_data.get("hash-average") or 0) > 0,
|
||||
missing=False,
|
||||
tuned=True,
|
||||
)
|
||||
)
|
||||
return boards
|
||||
|
||||
async def _get_pools(
|
||||
self, rpc_get_miner_status_summary: dict = None
|
||||
) -> list[PoolMetrics]:
|
||||
if rpc_get_miner_status_summary is None:
|
||||
try:
|
||||
rpc_get_miner_status_summary = await self.rpc.get_miner_status_summary()
|
||||
except APIError:
|
||||
return []
|
||||
pools = []
|
||||
msg_pools = rpc_get_miner_status_summary.get("msg", {}).get("pools", [])
|
||||
for idx, pool in enumerate(msg_pools):
|
||||
pools.append(
|
||||
PoolMetrics(
|
||||
index=idx,
|
||||
user=pool.get("account"),
|
||||
alive=pool.get("status") == "alive",
|
||||
active=pool.get("stratum-active"),
|
||||
url=pool.get("url"),
|
||||
)
|
||||
)
|
||||
return pools
|
||||
|
||||
async def _get_uptime(
|
||||
self, rpc_get_miner_status_summary: dict = None
|
||||
) -> int | None:
|
||||
if rpc_get_miner_status_summary is None:
|
||||
try:
|
||||
rpc_get_miner_status_summary = await self.rpc.get_miner_status_summary()
|
||||
except APIError:
|
||||
return None
|
||||
return (
|
||||
rpc_get_miner_status_summary.get("msg", {})
|
||||
.get("summary", {})
|
||||
.get("elapsed")
|
||||
)
|
||||
|
||||
async def _get_wattage(
|
||||
self, rpc_get_miner_status_summary: dict = None
|
||||
) -> float | None:
|
||||
if rpc_get_miner_status_summary is None:
|
||||
try:
|
||||
rpc_get_miner_status_summary = await self.rpc.get_miner_status_summary()
|
||||
except APIError:
|
||||
return None
|
||||
return (
|
||||
rpc_get_miner_status_summary.get("msg", {})
|
||||
.get("summary", {})
|
||||
.get("power-realtime")
|
||||
)
|
||||
|
||||
async def _get_hashrate(
|
||||
self, rpc_get_miner_status_summary: dict = None
|
||||
) -> float | None:
|
||||
if rpc_get_miner_status_summary is None:
|
||||
try:
|
||||
rpc_get_miner_status_summary = await self.rpc.get_miner_status_summary()
|
||||
except APIError:
|
||||
return None
|
||||
return (
|
||||
rpc_get_miner_status_summary.get("msg", {})
|
||||
.get("summary", {})
|
||||
.get("hash-realtime")
|
||||
)
|
||||
|
||||
async def _get_expected_hashrate(
|
||||
self, rpc_get_miner_status_summary: dict = None
|
||||
) -> float | None:
|
||||
if rpc_get_miner_status_summary is None:
|
||||
try:
|
||||
rpc_get_miner_status_summary = await self.rpc.get_miner_status_summary()
|
||||
except APIError:
|
||||
return None
|
||||
res = (
|
||||
rpc_get_miner_status_summary.get("msg", {})
|
||||
.get("summary", {})
|
||||
.get("factory-hash")
|
||||
)
|
||||
|
||||
if res == (-0.001 * self.expected_hashboards):
|
||||
return None
|
||||
return res
|
||||
|
||||
async def _get_env_temp(
|
||||
self, rpc_get_miner_status_summary: dict = None
|
||||
) -> float | None:
|
||||
if rpc_get_miner_status_summary is None:
|
||||
try:
|
||||
rpc_get_miner_status_summary = await self.rpc.get_miner_status_summary()
|
||||
except APIError:
|
||||
return None
|
||||
return (
|
||||
rpc_get_miner_status_summary.get("msg", {})
|
||||
.get("summary", {})
|
||||
.get("environment-temperature")
|
||||
)
|
||||
|
||||
@@ -233,9 +233,10 @@ class ElphapexMiner(StockFirmware):
|
||||
board_temp_data = list(
|
||||
filter(lambda x: not x == 0, board["temp_pcb"])
|
||||
)
|
||||
hashboards[board["index"]].temp = sum(board_temp_data) / len(
|
||||
board_temp_data
|
||||
)
|
||||
if not len(board_temp_data) == 0:
|
||||
hashboards[board["index"]].temp = sum(board_temp_data) / len(
|
||||
board_temp_data
|
||||
)
|
||||
chip_temp_data = list(
|
||||
filter(lambda x: not x == "", board["temp_chip"])
|
||||
)
|
||||
|
||||
@@ -13,24 +13,28 @@
|
||||
# See the License for the specific language governing permissions and -
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
from pyasic.miners.backends.btminer import BTMiner
|
||||
from pyasic.miners.backends.btminer import BTMiner, BTMinerV2
|
||||
|
||||
|
||||
class M7X(BTMiner):
|
||||
supports_autotuning = True
|
||||
supports_presets = True
|
||||
|
||||
|
||||
class M6X(BTMiner):
|
||||
supports_autotuning = True
|
||||
supports_presets = True
|
||||
|
||||
|
||||
class M5X(BTMiner):
|
||||
supports_autotuning = True
|
||||
supports_presets = True
|
||||
|
||||
|
||||
class M3X(BTMiner):
|
||||
supports_autotuning = True
|
||||
supports_presets = True
|
||||
|
||||
|
||||
class M2X(BTMiner):
|
||||
class M2X(BTMinerV2):
|
||||
pass
|
||||
|
||||
@@ -576,7 +576,7 @@ class MinerProtocol(Protocol):
|
||||
|
||||
|
||||
class BaseMiner(MinerProtocol):
|
||||
def __init__(self, ip: str) -> None:
|
||||
def __init__(self, ip: str, version: str | None = None) -> None:
|
||||
self.ip = ip
|
||||
|
||||
if self.expected_chips is None and self.raw_model is not None:
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
# See the License for the specific language governing permissions and -
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
from .byte import *
|
||||
from .mini_doge import *
|
||||
from .X5 import *
|
||||
from .XBox import *
|
||||
from .XMax import *
|
||||
|
||||
16
pyasic/miners/device/models/goldshell/byte/__init__.py
Normal file
16
pyasic/miners/device/models/goldshell/byte/__init__.py
Normal file
@@ -0,0 +1,16 @@
|
||||
# ------------------------------------------------------------------------------
|
||||
# Copyright 2025 Upstream Data Inc -
|
||||
# -
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); -
|
||||
# you may not use this file except in compliance with the License. -
|
||||
# You may obtain a copy of the License at -
|
||||
# -
|
||||
# http://www.apache.org/licenses/LICENSE-2.0 -
|
||||
# -
|
||||
# Unless required by applicable law or agreed to in writing, software -
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, -
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -
|
||||
# See the License for the specific language governing permissions and -
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
from .byte import Byte
|
||||
27
pyasic/miners/device/models/goldshell/byte/byte.py
Normal file
27
pyasic/miners/device/models/goldshell/byte/byte.py
Normal file
@@ -0,0 +1,27 @@
|
||||
# ------------------------------------------------------------------------------
|
||||
# Copyright 2025 Upstream Data Inc -
|
||||
# -
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); -
|
||||
# you may not use this file except in compliance with the License. -
|
||||
# You may obtain a copy of the License at -
|
||||
# -
|
||||
# http://www.apache.org/licenses/LICENSE-2.0 -
|
||||
# -
|
||||
# Unless required by applicable law or agreed to in writing, software -
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, -
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -
|
||||
# See the License for the specific language governing permissions and -
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
from pyasic.device.algorithm.base import GenericAlgo
|
||||
from pyasic.device.models import MinerModel
|
||||
from pyasic.miners.device.makes import GoldshellMake
|
||||
|
||||
|
||||
class Byte(GoldshellMake):
|
||||
raw_model = MinerModel.GOLDSHELL.Byte
|
||||
|
||||
expected_chips = 0
|
||||
expected_fans = 0
|
||||
expected_hashboards = 0
|
||||
algo = GenericAlgo
|
||||
16
pyasic/miners/device/models/goldshell/mini_doge/__init__.py
Normal file
16
pyasic/miners/device/models/goldshell/mini_doge/__init__.py
Normal file
@@ -0,0 +1,16 @@
|
||||
# ------------------------------------------------------------------------------
|
||||
# Copyright 2025 Upstream Data Inc -
|
||||
# -
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); -
|
||||
# you may not use this file except in compliance with the License. -
|
||||
# You may obtain a copy of the License at -
|
||||
# -
|
||||
# http://www.apache.org/licenses/LICENSE-2.0 -
|
||||
# -
|
||||
# Unless required by applicable law or agreed to in writing, software -
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, -
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -
|
||||
# See the License for the specific language governing permissions and -
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
from .mini_doge import MiniDoge
|
||||
27
pyasic/miners/device/models/goldshell/mini_doge/mini_doge.py
Normal file
27
pyasic/miners/device/models/goldshell/mini_doge/mini_doge.py
Normal file
@@ -0,0 +1,27 @@
|
||||
# ------------------------------------------------------------------------------
|
||||
# Copyright 2025 Upstream Data Inc -
|
||||
# -
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); -
|
||||
# you may not use this file except in compliance with the License. -
|
||||
# You may obtain a copy of the License at -
|
||||
# -
|
||||
# http://www.apache.org/licenses/LICENSE-2.0 -
|
||||
# -
|
||||
# Unless required by applicable law or agreed to in writing, software -
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, -
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -
|
||||
# See the License for the specific language governing permissions and -
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
from pyasic.device.algorithm import MinerAlgo
|
||||
from pyasic.device.models import MinerModel
|
||||
from pyasic.miners.device.makes import GoldshellMake
|
||||
|
||||
|
||||
class MiniDoge(GoldshellMake):
|
||||
raw_model = MinerModel.GOLDSHELL.MiniDoge
|
||||
|
||||
expected_chips = 40
|
||||
expected_fans = 2
|
||||
expected_hashboards = 1
|
||||
algo = MinerAlgo.SCRYPT
|
||||
@@ -40,5 +40,6 @@ class KS5M(IceRiverMake):
|
||||
raw_model = MinerModel.ICERIVER.KS5M
|
||||
|
||||
expected_fans = 4
|
||||
expected_chips = 18
|
||||
expected_hashboards = 3
|
||||
algo = MinerAlgo.KHEAVYHASH
|
||||
|
||||
@@ -82,6 +82,7 @@ MINER_CLASSES = {
|
||||
"ANTMINER KS5": BMMinerKS5,
|
||||
"ANTMINER KS5 PRO": BMMinerKS5Pro,
|
||||
"ANTMINER L7": BMMinerL7,
|
||||
"ANTMINER L7_I": BMMinerL7,
|
||||
"ANTMINER K7": BMMinerK7,
|
||||
"ANTMINER D7": BMMinerD7,
|
||||
"ANTMINER E9 PRO": BMMinerE9Pro,
|
||||
@@ -91,6 +92,7 @@ MINER_CLASSES = {
|
||||
"ANTMINER S9J": BMMinerS9j,
|
||||
"ANTMINER T9": BMMinerT9,
|
||||
"ANTMINER L9": BMMinerL9,
|
||||
"ANTMINER L9_I": BMMinerL9,
|
||||
"ANTMINER Z15": CGMinerZ15,
|
||||
"ANTMINER Z15 PRO": BMMinerZ15Pro,
|
||||
"ANTMINER S17": BMMinerS17,
|
||||
@@ -125,6 +127,7 @@ MINER_CLASSES = {
|
||||
"ANTMINER BHB68606": BMMinerS21, # ???
|
||||
"ANTMINER S21+": BMMinerS21Plus,
|
||||
"ANTMINER S21+ HYD.": BMMinerS21PlusHydro,
|
||||
"ANTMINER S21+ HYD": BMMinerS21PlusHydro,
|
||||
"ANTMINER S21 PRO": BMMinerS21Pro,
|
||||
"ANTMINER T21": BMMinerT21,
|
||||
"ANTMINER S21 HYD.": BMMinerS21Hydro,
|
||||
@@ -529,6 +532,8 @@ MINER_CLASSES = {
|
||||
"GOLDSHELL KDMAX": GoldshellKDMax,
|
||||
"GOLDSHELL KDBOXII": GoldshellKDBoxII,
|
||||
"GOLDSHELL KDBOXPRO": GoldshellKDBoxPro,
|
||||
"GOLDSHELL BYTE": GoldshellByte,
|
||||
"GOLDSHELL MINIDOGE": GoldshellMiniDoge,
|
||||
},
|
||||
MinerTypes.BRAIINS_OS: {
|
||||
None: BOSMiner,
|
||||
@@ -590,6 +595,7 @@ MINER_CLASSES = {
|
||||
"ANTMINER S19A PRO": VNishS19aPro,
|
||||
"ANTMINER S19 PRO A": VNishS19ProA,
|
||||
"ANTMINER S19 PRO HYD.": VNishS19ProHydro,
|
||||
"ANTMINER S19 PRO HYDRO": VNishS19ProHydro,
|
||||
"ANTMINER S19K PRO": VNishS19kPro,
|
||||
"ANTMINER T19": VNishT19,
|
||||
"ANTMINER T21": VNishT21,
|
||||
@@ -786,21 +792,32 @@ class MinerFactory:
|
||||
MinerTypes.VOLCMINER: self.get_miner_model_volcminer,
|
||||
MinerTypes.ELPHAPEX: self.get_miner_model_elphapex,
|
||||
}
|
||||
fn = miner_model_fns.get(miner_type)
|
||||
version = None
|
||||
miner_version_fns = {
|
||||
MinerTypes.WHATSMINER: self.get_miner_version_whatsminer,
|
||||
}
|
||||
model_fn = miner_model_fns.get(miner_type)
|
||||
version_fn = miner_version_fns.get(miner_type)
|
||||
|
||||
if fn is not None:
|
||||
if model_fn is not None:
|
||||
# noinspection PyArgumentList
|
||||
task = asyncio.create_task(fn(ip))
|
||||
task = asyncio.create_task(model_fn(ip))
|
||||
try:
|
||||
miner_model = await asyncio.wait_for(
|
||||
task, timeout=settings.get("factory_get_timeout", 3)
|
||||
)
|
||||
except asyncio.TimeoutError:
|
||||
pass
|
||||
if version_fn is not None:
|
||||
task = asyncio.create_task(version_fn(ip))
|
||||
try:
|
||||
version = await asyncio.wait_for(
|
||||
task, timeout=settings.get("factory_get_timeout", 3)
|
||||
)
|
||||
except asyncio.TimeoutError:
|
||||
pass
|
||||
miner = self._select_miner_from_classes(
|
||||
ip,
|
||||
miner_type=miner_type,
|
||||
miner_model=miner_model,
|
||||
ip, miner_type=miner_type, miner_model=miner_model, version=version
|
||||
)
|
||||
return miner
|
||||
|
||||
@@ -1065,6 +1082,45 @@ class MinerFactory:
|
||||
|
||||
return data
|
||||
|
||||
async def send_btminer_v3_api_command(self, ip, command):
|
||||
try:
|
||||
reader, writer = await asyncio.open_connection(ip, 4433)
|
||||
except (ConnectionError, OSError):
|
||||
return
|
||||
cmd = {"cmd": command}
|
||||
|
||||
try:
|
||||
# send the command
|
||||
json_cmd = json.dumps(cmd).encode("utf-8")
|
||||
length = len(json_cmd)
|
||||
writer.write(length.to_bytes(4, byteorder="little"))
|
||||
writer.write(json_cmd)
|
||||
await writer.drain()
|
||||
|
||||
# receive all the data
|
||||
resp_len = await reader.readexactly(4)
|
||||
data = await reader.readexactly(
|
||||
int.from_bytes(resp_len, byteorder="little")
|
||||
)
|
||||
|
||||
writer.close()
|
||||
await writer.wait_closed()
|
||||
except asyncio.CancelledError:
|
||||
writer.close()
|
||||
await writer.wait_closed()
|
||||
return
|
||||
except (ConnectionError, OSError):
|
||||
return
|
||||
if data == b"Socket connect failed: Connection refused\n":
|
||||
return
|
||||
|
||||
try:
|
||||
data = json.loads(data)
|
||||
except json.JSONDecodeError:
|
||||
return {}
|
||||
|
||||
return data
|
||||
|
||||
@staticmethod
|
||||
async def _fix_api_data(data: bytes) -> str:
|
||||
if data.endswith(b"\x00"):
|
||||
@@ -1103,13 +1159,14 @@ class MinerFactory:
|
||||
ip: ipaddress.ip_address,
|
||||
miner_model: str | None,
|
||||
miner_type: MinerTypes | None,
|
||||
version: str | None = None,
|
||||
) -> AnyMiner | None:
|
||||
# special case since hiveon miners return web results copying the antminer stock FW
|
||||
if "HIVEON" in str(miner_model).upper():
|
||||
miner_model = str(miner_model).upper().replace(" HIVEON", "")
|
||||
miner_type = MinerTypes.HIVEON
|
||||
try:
|
||||
return MINER_CLASSES[miner_type][str(miner_model).upper()](ip)
|
||||
return MINER_CLASSES[miner_type][str(miner_model).upper()](ip, version)
|
||||
except LookupError:
|
||||
if miner_type in MINER_CLASSES:
|
||||
if miner_model is not None:
|
||||
@@ -1117,8 +1174,8 @@ class MinerFactory:
|
||||
f"Partially supported miner found: {miner_model}, type: {miner_type}, please open an issue with miner data "
|
||||
f"and this model on GitHub (https://github.com/UpstreamData/pyasic/issues)."
|
||||
)
|
||||
return MINER_CLASSES[miner_type][None](ip)
|
||||
return UnknownMiner(str(ip))
|
||||
return MINER_CLASSES[miner_type][None](ip, version)
|
||||
return UnknownMiner(str(ip), version)
|
||||
|
||||
async def get_miner_model_antminer(self, ip: str) -> str | None:
|
||||
tasks = [
|
||||
@@ -1184,9 +1241,25 @@ class MinerFactory:
|
||||
try:
|
||||
miner_model = sock_json_data["DEVDETAILS"][0]["Model"].replace("_", "")
|
||||
miner_model = miner_model[:-1] + "0"
|
||||
|
||||
return miner_model
|
||||
except (TypeError, LookupError):
|
||||
sock_json_data_v3 = await self.send_btminer_v3_api_command(
|
||||
ip, "get.device.info"
|
||||
)
|
||||
try:
|
||||
miner_model = sock_json_data_v3["msg"]["miner"]["type"].replace("_", "")
|
||||
miner_model = miner_model[:-1] + "0"
|
||||
|
||||
return miner_model
|
||||
except (TypeError, LookupError):
|
||||
pass
|
||||
|
||||
async def get_miner_version_whatsminer(self, ip: str) -> str | None:
|
||||
sock_json_data = await self.send_api_command(ip, "get_version")
|
||||
try:
|
||||
version = sock_json_data["Msg"]["fw_ver"]
|
||||
return version
|
||||
except LookupError:
|
||||
pass
|
||||
|
||||
async def get_miner_model_avalonminer(self, ip: str) -> str | None:
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
# See the License for the specific language governing permissions and -
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
from .byte import *
|
||||
from .mini_doge import *
|
||||
from .X5 import *
|
||||
from .XBox import *
|
||||
from .XMax import *
|
||||
|
||||
16
pyasic/miners/goldshell/bfgminer/byte/__init__.py
Normal file
16
pyasic/miners/goldshell/bfgminer/byte/__init__.py
Normal file
@@ -0,0 +1,16 @@
|
||||
# ------------------------------------------------------------------------------
|
||||
# Copyright 2025 Upstream Data Inc -
|
||||
# -
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); -
|
||||
# you may not use this file except in compliance with the License. -
|
||||
# You may obtain a copy of the License at -
|
||||
# -
|
||||
# http://www.apache.org/licenses/LICENSE-2.0 -
|
||||
# -
|
||||
# Unless required by applicable law or agreed to in writing, software -
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, -
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -
|
||||
# See the License for the specific language governing permissions and -
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
from .byte import GoldshellByte
|
||||
349
pyasic/miners/goldshell/bfgminer/byte/byte.py
Normal file
349
pyasic/miners/goldshell/bfgminer/byte/byte.py
Normal file
@@ -0,0 +1,349 @@
|
||||
# ------------------------------------------------------------------------------
|
||||
# Copyright 2025 Upstream Data Inc -
|
||||
# -
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); -
|
||||
# you may not use this file except in compliance with the License. -
|
||||
# You may obtain a copy of the License at -
|
||||
# -
|
||||
# http://www.apache.org/licenses/LICENSE-2.0 -
|
||||
# -
|
||||
# Unless required by applicable law or agreed to in writing, software -
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, -
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -
|
||||
# See the License for the specific language governing permissions and -
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
from typing import List, Optional, Union
|
||||
|
||||
from pyasic.config import MinerConfig
|
||||
from pyasic.data import Fan, MinerData
|
||||
from pyasic.data.boards import HashBoard
|
||||
from pyasic.data.pools import PoolMetrics, PoolUrl
|
||||
from pyasic.device.algorithm import AlgoHashRate, MinerAlgo
|
||||
from pyasic.errors import APIError
|
||||
from pyasic.miners.backends import GoldshellMiner
|
||||
from pyasic.miners.data import (
|
||||
DataFunction,
|
||||
DataLocations,
|
||||
DataOptions,
|
||||
RPCAPICommand,
|
||||
WebAPICommand,
|
||||
)
|
||||
from pyasic.miners.device.models import Byte
|
||||
|
||||
ALGORITHM_SCRYPT_NAME = "scrypt(LTC)"
|
||||
ALGORITHM_ZKSNARK_NAME = "zkSNARK(ALEO)"
|
||||
EXPECTED_CHIPS_PER_SCRYPT_BOARD = 5
|
||||
EXPECTED_CHIPS_PER_ZKSNARK_BOARD = 3
|
||||
|
||||
GOLDSHELL_BYTE_DATA_LOC = DataLocations(
|
||||
**{
|
||||
str(DataOptions.MAC): DataFunction(
|
||||
"_get_mac",
|
||||
[WebAPICommand("web_setting", "setting")],
|
||||
),
|
||||
str(DataOptions.API_VERSION): DataFunction(
|
||||
"_get_api_ver",
|
||||
[WebAPICommand("web_setting", "version")],
|
||||
),
|
||||
str(DataOptions.FW_VERSION): DataFunction(
|
||||
"_get_fw_ver",
|
||||
[WebAPICommand("web_status", "status")],
|
||||
),
|
||||
str(DataOptions.HASHRATE): DataFunction(
|
||||
"_get_hashrate",
|
||||
[RPCAPICommand("rpc_devs", "devs")],
|
||||
),
|
||||
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
|
||||
"_get_expected_hashrate",
|
||||
[RPCAPICommand("rpc_devs", "devs")],
|
||||
),
|
||||
str(DataOptions.HASHBOARDS): DataFunction(
|
||||
"_get_hashboards",
|
||||
[
|
||||
RPCAPICommand("rpc_devs", "devs"),
|
||||
RPCAPICommand("rpc_devdetails", "devdetails"),
|
||||
],
|
||||
),
|
||||
str(DataOptions.FANS): DataFunction(
|
||||
"_get_fans",
|
||||
[RPCAPICommand("rpc_devs", "devs")],
|
||||
),
|
||||
str(DataOptions.POOLS): DataFunction(
|
||||
"_get_pools",
|
||||
[RPCAPICommand("rpc_pools", "pools")],
|
||||
),
|
||||
str(DataOptions.UPTIME): DataFunction(
|
||||
"_get_uptime",
|
||||
[WebAPICommand("web_devs", "devs")],
|
||||
),
|
||||
str(DataOptions.WATTAGE): DataFunction(
|
||||
"_get_wattage",
|
||||
[WebAPICommand("web_devs", "devs")],
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
class GoldshellByte(GoldshellMiner, Byte):
|
||||
data_locations = GOLDSHELL_BYTE_DATA_LOC
|
||||
supports_shutdown = False
|
||||
supports_power_modes = False
|
||||
web_devs: dict | None = None
|
||||
|
||||
async def get_data(
|
||||
self,
|
||||
allow_warning: bool = False,
|
||||
include: List[Union[str, DataOptions]] = None,
|
||||
exclude: List[Union[str, DataOptions]] = None,
|
||||
) -> MinerData:
|
||||
if self.web_devs is None:
|
||||
try:
|
||||
self.web_devs = await self.web.devs()
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
scrypt_board_count = 0
|
||||
zksnark_board_count = 0
|
||||
|
||||
for minfo in self.web_devs.get("minfos", []):
|
||||
algo_name = minfo.get("name")
|
||||
|
||||
for _ in minfo.get("infos", []):
|
||||
self.expected_hashboards += 1
|
||||
self.expected_fans += 1
|
||||
|
||||
if algo_name == ALGORITHM_SCRYPT_NAME:
|
||||
scrypt_board_count += 1
|
||||
elif algo_name == ALGORITHM_ZKSNARK_NAME:
|
||||
zksnark_board_count += 1
|
||||
|
||||
self.expected_chips = (EXPECTED_CHIPS_PER_SCRYPT_BOARD * scrypt_board_count) + (
|
||||
EXPECTED_CHIPS_PER_ZKSNARK_BOARD * zksnark_board_count
|
||||
)
|
||||
|
||||
if scrypt_board_count > 0 and zksnark_board_count == 0:
|
||||
self.algo = MinerAlgo.SCRYPT
|
||||
elif zksnark_board_count > 0 and scrypt_board_count == 0:
|
||||
self.algo = MinerAlgo.ZKSNARK
|
||||
|
||||
data = await super().get_data(allow_warning, include, exclude)
|
||||
data.expected_chips = self.expected_chips
|
||||
|
||||
return data
|
||||
|
||||
async def get_config(self) -> MinerConfig:
|
||||
try:
|
||||
pools = await self.web.pools()
|
||||
except APIError:
|
||||
return self.config
|
||||
|
||||
self.config = MinerConfig.from_goldshell_byte(pools)
|
||||
return self.config
|
||||
|
||||
async def _get_api_ver(self, web_setting: dict = None) -> Optional[str]:
|
||||
if web_setting is None:
|
||||
try:
|
||||
web_setting = await self.web.setting()
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
if web_setting is not None:
|
||||
try:
|
||||
version = web_setting.get("version")
|
||||
if version is not None:
|
||||
self.api_ver = version.strip("v")
|
||||
return self.api_ver
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
return self.api_ver
|
||||
|
||||
async def _get_expected_hashrate(
|
||||
self, rpc_devs: dict = None
|
||||
) -> Optional[AlgoHashRate]:
|
||||
if rpc_devs is None:
|
||||
try:
|
||||
rpc_devs = await self.rpc.devs()
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
total_hash_rate_mh = 0
|
||||
|
||||
if rpc_devs is not None:
|
||||
for board in rpc_devs.get("DEVS", []):
|
||||
algo_name = board.get("pool")
|
||||
|
||||
if algo_name == ALGORITHM_SCRYPT_NAME:
|
||||
total_hash_rate_mh += (
|
||||
self.algo.hashrate(
|
||||
rate=float(board.get("estimate_hash_rate", 0)),
|
||||
unit=self.algo.unit.H,
|
||||
)
|
||||
.into(self.algo.unit.MH)
|
||||
.rate
|
||||
)
|
||||
elif algo_name == ALGORITHM_ZKSNARK_NAME:
|
||||
total_hash_rate_mh += float(board.get("theory_hash", 0))
|
||||
|
||||
hash_rate = self.algo.hashrate(
|
||||
rate=total_hash_rate_mh, unit=self.algo.unit.MH
|
||||
).into(self.algo.unit.default)
|
||||
|
||||
return hash_rate
|
||||
|
||||
async def _get_hashrate(self, rpc_devs: dict = None) -> Optional[AlgoHashRate]:
|
||||
if rpc_devs is None:
|
||||
try:
|
||||
rpc_devs = await self.rpc.devs()
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
total_hash_rate_mh = 0
|
||||
|
||||
if rpc_devs is not None:
|
||||
for board in rpc_devs.get("DEVS", []):
|
||||
total_hash_rate_mh += float(board.get("MHS 20s", 0))
|
||||
|
||||
hash_rate = self.algo.hashrate(
|
||||
rate=total_hash_rate_mh, unit=self.algo.unit.MH
|
||||
).into(self.algo.unit.default)
|
||||
|
||||
return hash_rate
|
||||
|
||||
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 index, pool_info in enumerate(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"),
|
||||
active=pool_info.get("Stratum Active"),
|
||||
alive=pool_info.get("Status") == "Alive",
|
||||
url=pool_url,
|
||||
user=pool_info.get("User"),
|
||||
index=index,
|
||||
)
|
||||
pools_data.append(pool_data)
|
||||
except LookupError:
|
||||
pass
|
||||
return pools_data
|
||||
|
||||
async def _get_hashboards(
|
||||
self, rpc_devs: dict = None, rpc_devdetails: dict = None
|
||||
) -> List[HashBoard]:
|
||||
if rpc_devs is None:
|
||||
try:
|
||||
rpc_devs = await self.rpc.devs()
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
hashboards = [
|
||||
HashBoard(slot=i, expected_chips=self.expected_chips)
|
||||
for i in range(self.expected_hashboards)
|
||||
]
|
||||
|
||||
if rpc_devs is not None:
|
||||
for board in rpc_devs.get("DEVS", []):
|
||||
b_id = board["PGA"]
|
||||
hashboards[b_id].hashrate = self.algo.hashrate(
|
||||
rate=float(board["MHS 20s"]), unit=self.algo.unit.MH
|
||||
).into(self.algo.unit.default)
|
||||
hashboards[b_id].chip_temp = board["tstemp-1"]
|
||||
hashboards[b_id].temp = board["tstemp-2"]
|
||||
hashboards[b_id].voltage = board["voltage"]
|
||||
hashboards[b_id].active = board["Status"] == "Alive"
|
||||
hashboards[b_id].missing = False
|
||||
|
||||
algo_name = board.get("pool")
|
||||
|
||||
if algo_name == ALGORITHM_SCRYPT_NAME:
|
||||
hashboards[b_id].expected_chips = EXPECTED_CHIPS_PER_SCRYPT_BOARD
|
||||
elif algo_name == ALGORITHM_ZKSNARK_NAME:
|
||||
hashboards[b_id].expected_chips = EXPECTED_CHIPS_PER_ZKSNARK_BOARD
|
||||
|
||||
if rpc_devdetails is None:
|
||||
try:
|
||||
rpc_devdetails = await self.rpc.devdetails()
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
if rpc_devdetails is not None:
|
||||
for board in rpc_devdetails.get("DEVS", []):
|
||||
b_id = board["DEVDETAILS"]
|
||||
hashboards[b_id].chips = board["chips-nr"]
|
||||
|
||||
return hashboards
|
||||
|
||||
async def _get_fans(self, rpc_devs: dict = None) -> List[Fan]:
|
||||
if self.expected_fans is None:
|
||||
return []
|
||||
|
||||
if rpc_devs is None:
|
||||
try:
|
||||
rpc_devs = await self.rpc.devs()
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
fans_data = []
|
||||
|
||||
if rpc_devs is not None:
|
||||
for board in rpc_devs.get("DEVS", []):
|
||||
if board.get("PGA") is not None:
|
||||
try:
|
||||
b_id = board["PGA"]
|
||||
fan_speed = board[f"fan{b_id}"]
|
||||
fans_data.append(fan_speed)
|
||||
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
fans = [Fan(speed=d) if d else Fan() for d in fans_data]
|
||||
|
||||
return fans
|
||||
|
||||
async def _get_uptime(self, web_devs: dict = None) -> Optional[int]:
|
||||
if web_devs is None:
|
||||
try:
|
||||
web_devs = await self.web.devs()
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
if web_devs is not None:
|
||||
try:
|
||||
for minfo in self.web_devs.get("minfos", []):
|
||||
for info in minfo.get("infos", []):
|
||||
uptime = int(float(info["time"]))
|
||||
return uptime
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
return None
|
||||
|
||||
async def _get_wattage(self, web_devs: dict = None) -> Optional[int]:
|
||||
if web_devs is None:
|
||||
try:
|
||||
web_devs = await self.web.devs()
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
if web_devs is not None:
|
||||
try:
|
||||
for minfo in self.web_devs.get("minfos", []):
|
||||
for info in minfo.get("infos", []):
|
||||
wattage = int(float(info["power"]))
|
||||
return wattage
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
return None
|
||||
16
pyasic/miners/goldshell/bfgminer/mini_doge/__init__.py
Normal file
16
pyasic/miners/goldshell/bfgminer/mini_doge/__init__.py
Normal file
@@ -0,0 +1,16 @@
|
||||
# ------------------------------------------------------------------------------
|
||||
# Copyright 2025 Upstream Data Inc -
|
||||
# -
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); -
|
||||
# you may not use this file except in compliance with the License. -
|
||||
# You may obtain a copy of the License at -
|
||||
# -
|
||||
# http://www.apache.org/licenses/LICENSE-2.0 -
|
||||
# -
|
||||
# Unless required by applicable law or agreed to in writing, software -
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, -
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -
|
||||
# See the License for the specific language governing permissions and -
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
from .mini_doge import GoldshellMiniDoge
|
||||
179
pyasic/miners/goldshell/bfgminer/mini_doge/mini_doge.py
Normal file
179
pyasic/miners/goldshell/bfgminer/mini_doge/mini_doge.py
Normal file
@@ -0,0 +1,179 @@
|
||||
# ------------------------------------------------------------------------------
|
||||
# Copyright 2025 Upstream Data Inc -
|
||||
# -
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); -
|
||||
# you may not use this file except in compliance with the License. -
|
||||
# You may obtain a copy of the License at -
|
||||
# -
|
||||
# http://www.apache.org/licenses/LICENSE-2.0 -
|
||||
# -
|
||||
# Unless required by applicable law or agreed to in writing, software -
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, -
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -
|
||||
# See the License for the specific language governing permissions and -
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
from typing import List, Optional
|
||||
|
||||
from pyasic.config import MinerConfig
|
||||
from pyasic.data.boards import HashBoard
|
||||
from pyasic.device.algorithm import AlgoHashRate
|
||||
from pyasic.errors import APIError
|
||||
from pyasic.logger import logger
|
||||
from pyasic.miners.backends import GoldshellMiner
|
||||
from pyasic.miners.data import (
|
||||
DataFunction,
|
||||
DataLocations,
|
||||
DataOptions,
|
||||
RPCAPICommand,
|
||||
WebAPICommand,
|
||||
)
|
||||
from pyasic.miners.device.models import MiniDoge
|
||||
|
||||
GOLDSHELL_MINI_DOGE_DATA_LOC = DataLocations(
|
||||
**{
|
||||
str(DataOptions.MAC): DataFunction(
|
||||
"_get_mac",
|
||||
[WebAPICommand("web_setting", "setting")],
|
||||
),
|
||||
str(DataOptions.API_VERSION): DataFunction(
|
||||
"_get_api_ver",
|
||||
[RPCAPICommand("rpc_version", "version")],
|
||||
),
|
||||
str(DataOptions.FW_VERSION): DataFunction(
|
||||
"_get_fw_ver",
|
||||
[WebAPICommand("web_status", "status")],
|
||||
),
|
||||
str(DataOptions.HASHRATE): DataFunction(
|
||||
"_get_hashrate",
|
||||
[RPCAPICommand("rpc_summary", "summary")],
|
||||
),
|
||||
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
|
||||
"_get_expected_hashrate",
|
||||
[RPCAPICommand("rpc_devs", "devs")],
|
||||
),
|
||||
str(DataOptions.HASHBOARDS): DataFunction(
|
||||
"_get_hashboards",
|
||||
[
|
||||
RPCAPICommand("rpc_devs", "devs"),
|
||||
RPCAPICommand("rpc_devdetails", "devdetails"),
|
||||
],
|
||||
),
|
||||
str(DataOptions.FANS): DataFunction(
|
||||
"_get_fans",
|
||||
[RPCAPICommand("rpc_stats", "stats")],
|
||||
),
|
||||
str(DataOptions.POOLS): DataFunction(
|
||||
"_get_pools",
|
||||
[RPCAPICommand("rpc_pools", "pools")],
|
||||
),
|
||||
str(DataOptions.UPTIME): DataFunction(
|
||||
"_get_uptime",
|
||||
[WebAPICommand("web_devs", "devs")],
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
class GoldshellMiniDoge(GoldshellMiner, MiniDoge):
|
||||
data_locations = GOLDSHELL_MINI_DOGE_DATA_LOC
|
||||
supports_shutdown = False
|
||||
supports_power_modes = False
|
||||
|
||||
async def get_config(self) -> MinerConfig:
|
||||
try:
|
||||
pools = await self.web.pools()
|
||||
except APIError:
|
||||
return self.config
|
||||
|
||||
self.config = MinerConfig.from_goldshell_list(pools)
|
||||
return self.config
|
||||
|
||||
async def _get_expected_hashrate(
|
||||
self, rpc_devs: dict = None
|
||||
) -> Optional[AlgoHashRate]:
|
||||
if rpc_devs is None:
|
||||
try:
|
||||
rpc_devs = await self.rpc.devs()
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
if rpc_devs is not None:
|
||||
try:
|
||||
hash_rate = rpc_devs["DEVS"][0]["estimate_hash_rate"]
|
||||
return self.algo.hashrate(
|
||||
rate=float(hash_rate), unit=self.algo.unit.H
|
||||
).into(self.algo.unit.default)
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
return None
|
||||
|
||||
async def _get_hashboards(
|
||||
self, rpc_devs: dict = None, rpc_devdetails: dict = None
|
||||
) -> List[HashBoard]:
|
||||
if rpc_devs is None:
|
||||
try:
|
||||
rpc_devs = await self.rpc.devs()
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
hashboards = [
|
||||
HashBoard(slot=i, expected_chips=self.expected_chips)
|
||||
for i in range(self.expected_hashboards)
|
||||
]
|
||||
|
||||
if rpc_devs is not None:
|
||||
if rpc_devs.get("DEVS"):
|
||||
for board in rpc_devs["DEVS"]:
|
||||
if board.get("ID") is not None:
|
||||
try:
|
||||
b_id = board["ID"]
|
||||
hashboards[b_id].hashrate = self.algo.hashrate(
|
||||
rate=float(board["MHS 20s"]), unit=self.algo.unit.MH
|
||||
).into(self.algo.unit.default)
|
||||
hashboards[b_id].chip_temp = board["tstemp-0"]
|
||||
hashboards[b_id].temp = board["tstemp-1"]
|
||||
hashboards[b_id].voltage = board["voltage"]
|
||||
hashboards[b_id].active = board["Status"] == "Alive"
|
||||
hashboards[b_id].missing = False
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
logger.error(self, rpc_devs)
|
||||
|
||||
if rpc_devdetails is None:
|
||||
try:
|
||||
rpc_devdetails = await self.rpc.devdetails()
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
if rpc_devdetails is not None:
|
||||
if rpc_devdetails.get("DEVS"):
|
||||
for board in rpc_devdetails["DEVS"]:
|
||||
if board.get("ID") is not None:
|
||||
try:
|
||||
b_id = board["ID"]
|
||||
hashboards[b_id].chips = board["chips-nr"]
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
logger.error(self, rpc_devdetails)
|
||||
|
||||
return hashboards
|
||||
|
||||
async def _get_uptime(self, web_devs: dict = None) -> Optional[int]:
|
||||
if web_devs is None:
|
||||
try:
|
||||
web_devs = await self.web.devs()
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
if web_devs is not None:
|
||||
try:
|
||||
uptime = int(web_devs["data"][0]["time"])
|
||||
return uptime
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
return None
|
||||
@@ -136,17 +136,16 @@ class BaseMinerRPCAPI:
|
||||
self.send_command(cmd, allow_warning=allow_warning)
|
||||
)
|
||||
|
||||
await asyncio.gather(*[tasks[cmd] for cmd in tasks], return_exceptions=True)
|
||||
results = await asyncio.gather(
|
||||
*[tasks[cmd] for cmd in tasks], return_exceptions=True
|
||||
)
|
||||
|
||||
data = {}
|
||||
for cmd in tasks:
|
||||
try:
|
||||
result = tasks[cmd].result()
|
||||
for cmd, result in zip(tasks.keys(), results):
|
||||
if not isinstance(result, (APIError, Exception)):
|
||||
if result is None or result == {}:
|
||||
result = {}
|
||||
data[cmd] = [result]
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
return data
|
||||
|
||||
@@ -253,10 +252,10 @@ If you are sure you want to use this command please use API.send_command("{comma
|
||||
# some json from the API returns with a null byte (\x00) on the end
|
||||
if data.endswith(b"\x00"):
|
||||
# handle the null byte
|
||||
str_data = data.decode("utf-8")[:-1]
|
||||
str_data = data.decode("utf-8", errors="replace")[:-1]
|
||||
else:
|
||||
# no null byte
|
||||
str_data = data.decode("utf-8")
|
||||
str_data = data.decode("utf-8", errors="replace")
|
||||
# fix an error with a btminer return having an extra comma that breaks json.loads()
|
||||
str_data = str_data.replace(",}", "}")
|
||||
# fix an error with a btminer return having a newline that breaks json.loads()
|
||||
|
||||
@@ -23,14 +23,16 @@ import json
|
||||
import logging
|
||||
import re
|
||||
import struct
|
||||
from typing import Literal, Union
|
||||
import warnings
|
||||
from asyncio import Future, StreamReader, StreamWriter
|
||||
from typing import Any, AsyncGenerator, Callable, Literal, Union
|
||||
|
||||
import httpx
|
||||
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
||||
from passlib.handlers.md5_crypt import md5_crypt
|
||||
|
||||
from pyasic import settings
|
||||
from pyasic.errors import APIError
|
||||
from pyasic.errors import APIError, APIWarning
|
||||
from pyasic.misc import api_min_version, validate_command_output
|
||||
from pyasic.rpc.base import BaseMinerRPCAPI
|
||||
|
||||
@@ -250,13 +252,13 @@ class BTMinerRPCAPI(BaseMinerRPCAPI):
|
||||
except APIError as e:
|
||||
if not e.message == "can't access write cmd":
|
||||
raise
|
||||
try:
|
||||
await self.open_api()
|
||||
except Exception as e:
|
||||
raise APIError("Failed to open whatsminer API.") from e
|
||||
return await self._send_privileged_command(
|
||||
command=command, ignore_errors=ignore_errors, timeout=timeout, **kwargs
|
||||
)
|
||||
# try:
|
||||
# await self.open_api()
|
||||
# except Exception as e:
|
||||
# raise APIError("Failed to open whatsminer API.") from e
|
||||
# return await self._send_privileged_command(
|
||||
# command=command, ignore_errors=ignore_errors, timeout=timeout, **kwargs
|
||||
# )
|
||||
|
||||
async def _send_privileged_command(
|
||||
self,
|
||||
@@ -291,6 +293,7 @@ class BTMinerRPCAPI(BaseMinerRPCAPI):
|
||||
|
||||
try:
|
||||
data = parse_btminer_priviledge_data(self.token, data)
|
||||
print(data)
|
||||
except Exception as e:
|
||||
logging.info(f"{str(self.ip)}: {e}")
|
||||
|
||||
@@ -1100,3 +1103,318 @@ class BTMinerRPCAPI(BaseMinerRPCAPI):
|
||||
</details>
|
||||
"""
|
||||
return await self.send_command("get_error_code", allow_warning=False)
|
||||
|
||||
|
||||
class BTMinerV3RPCAPI(BaseMinerRPCAPI):
|
||||
def __init__(self, ip: str, port: int = 4433, api_ver: str = "0.0.0"):
|
||||
super().__init__(ip, port, api_ver=api_ver)
|
||||
|
||||
self.salt = None
|
||||
self.pwd = "super"
|
||||
|
||||
async def multicommand(self, *commands: str, allow_warning: bool = True) -> dict:
|
||||
"""Creates and sends multiple commands as one command to the miner.
|
||||
|
||||
Parameters:
|
||||
*commands: The commands to send as a multicommand to the miner.
|
||||
allow_warning: A boolean to supress APIWarnings.
|
||||
|
||||
"""
|
||||
commands = self._check_commands(*commands)
|
||||
data = await self._send_split_multicommand(*commands)
|
||||
data["multicommand"] = True
|
||||
return data
|
||||
|
||||
async def send_command(
|
||||
self, command: str, parameters: Any = None, **kwargs
|
||||
) -> dict:
|
||||
if ":" in command:
|
||||
parameters = command.split(":")[1]
|
||||
command = command.split(":")[0]
|
||||
cmd = {"cmd": command}
|
||||
if parameters is not None:
|
||||
cmd["param"] = parameters
|
||||
|
||||
if command.startswith("set."):
|
||||
salt = await self.get_salt()
|
||||
ts = int(datetime.datetime.now().timestamp())
|
||||
cmd["ts"] = ts
|
||||
token_str = cmd["cmd"] + self.pwd + salt + str(ts)
|
||||
token_hashed = bytearray(
|
||||
base64.b64encode(hashlib.sha256(token_str.encode("utf-8")).digest())
|
||||
)
|
||||
b_arr = bytearray(token_hashed)
|
||||
b_arr[8] = 0
|
||||
str_token = b_arr.split(b"\x00")[0].decode("utf-8")
|
||||
cmd["account"] = "super"
|
||||
cmd["token"] = str_token
|
||||
|
||||
# send the command
|
||||
ser = json.dumps(cmd).encode("utf-8")
|
||||
header = struct.pack("<I", len(ser))
|
||||
return json.loads(
|
||||
await self._send_bytes(header + json.dumps(cmd).encode("utf-8"))
|
||||
)
|
||||
|
||||
async def _send_bytes(
|
||||
self,
|
||||
data: bytes,
|
||||
*,
|
||||
port: int = None,
|
||||
timeout: int = 100,
|
||||
) -> bytes:
|
||||
if port is None:
|
||||
port = self.port
|
||||
logging.debug(f"{self} - ([Hidden] Send Bytes) - Sending")
|
||||
try:
|
||||
# get reader and writer streams
|
||||
reader, writer = await asyncio.open_connection(str(self.ip), port)
|
||||
# handle OSError 121
|
||||
except OSError as e:
|
||||
if e.errno == 121:
|
||||
logging.warning(
|
||||
f"{self} - ([Hidden] Send Bytes) - Semaphore timeout expired."
|
||||
)
|
||||
return b"{}"
|
||||
|
||||
# send the command
|
||||
try:
|
||||
data_task = asyncio.create_task(self._read_bytes(reader, timeout=timeout))
|
||||
logging.debug(f"{self} - ([Hidden] Send Bytes) - Writing")
|
||||
writer.write(data)
|
||||
logging.debug(f"{self} - ([Hidden] Send Bytes) - Draining")
|
||||
await writer.drain()
|
||||
|
||||
await data_task
|
||||
ret_data = data_task.result()
|
||||
except TimeoutError:
|
||||
logging.warning(f"{self} - ([Hidden] Send Bytes) - Read timeout expired.")
|
||||
return b"{}"
|
||||
|
||||
# close the connection
|
||||
logging.debug(f"{self} - ([Hidden] Send Bytes) - Closing")
|
||||
writer.close()
|
||||
await writer.wait_closed()
|
||||
|
||||
return ret_data
|
||||
|
||||
def _check_commands(self, *commands) -> list:
|
||||
return_commands = []
|
||||
|
||||
for command in commands:
|
||||
if command.startswith("get.") or command.startswith("set."):
|
||||
return_commands.append(command)
|
||||
else:
|
||||
warnings.warn(
|
||||
f"""Removing incorrect command: {command}
|
||||
If you are sure you want to use this command please use API.send_command("{command}", ignore_errors=True) instead.""",
|
||||
APIWarning,
|
||||
)
|
||||
return return_commands
|
||||
|
||||
async def _read_bytes(self, reader: asyncio.StreamReader, timeout: int) -> bytes:
|
||||
ret_data = b""
|
||||
|
||||
# loop to receive all the data
|
||||
logging.debug(f"{self} - ([Hidden] Send Bytes) - Receiving")
|
||||
try:
|
||||
header = await reader.readexactly(4)
|
||||
length = struct.unpack("<I", header)[0]
|
||||
ret_data = await reader.readexactly(length)
|
||||
except (asyncio.CancelledError, asyncio.TimeoutError) as e:
|
||||
raise e
|
||||
except Exception as e:
|
||||
logging.warning(f"{self} - ([Hidden] Send Bytes) - API Command Error {e}")
|
||||
return ret_data
|
||||
|
||||
async def get_salt(self) -> str:
|
||||
if self.salt is not None:
|
||||
return self.salt
|
||||
data = await self.send_command("get.device.info", "salt")
|
||||
self.salt = data["msg"]["salt"]
|
||||
return self.salt
|
||||
|
||||
async def get_miner_report(self) -> AsyncGenerator[dict, None]:
|
||||
if self.writer is None:
|
||||
await self.connect()
|
||||
|
||||
result = asyncio.Queue()
|
||||
|
||||
async def callback(data: dict):
|
||||
await result.put(data)
|
||||
|
||||
cb_fn = callback
|
||||
|
||||
try:
|
||||
self.cmd_callbacks["get.miner.report"].add(cb_fn)
|
||||
while True:
|
||||
yield await result.get()
|
||||
if self.writer.is_closing():
|
||||
break
|
||||
finally:
|
||||
self.cmd_callbacks["get.miner.report"].remove(cb_fn)
|
||||
|
||||
async def get_system_setting(self) -> dict | None:
|
||||
return await self.send_command("get.system.setting")
|
||||
|
||||
async def get_miner_status_summary(self) -> dict | None:
|
||||
return await self.send_command("get.miner.status", parameters="summary")
|
||||
|
||||
async def get_miner_status_edevs(self) -> dict | None:
|
||||
return await self.send_command("get.miner.status", parameters="edevs")
|
||||
|
||||
async def get_miner_status_pools(self) -> dict | None:
|
||||
return await self.send_command("get.miner.status", parameters="pools")
|
||||
|
||||
async def get_miner_history(self) -> dict | None:
|
||||
data = await self.send_command(
|
||||
"get.miner.history",
|
||||
parameters={
|
||||
"start": "1",
|
||||
"stop": str(datetime.datetime.now().timestamp()),
|
||||
},
|
||||
)
|
||||
ret = {}
|
||||
result = data.get("msg")
|
||||
if result is not None:
|
||||
unparsed = result["Data"].strip()
|
||||
for item in unparsed.split(" "):
|
||||
list_item = item.split(",")
|
||||
timestamp = int(list_item.pop(0))
|
||||
ret[timestamp] = list_item
|
||||
return ret
|
||||
|
||||
async def get_psu_command(self):
|
||||
return await self.send_command("get.psu.command")
|
||||
|
||||
async def get_miner_setting(self) -> dict | None:
|
||||
return await self.send_command("get.miner.setting")
|
||||
|
||||
async def get_device_info(self) -> dict | None:
|
||||
return await self.send_command("get.device.info")
|
||||
|
||||
async def get_log_download(self) -> dict | None:
|
||||
return await self.send_command("get.log.download")
|
||||
|
||||
async def get_fan_setting(self) -> dict | None:
|
||||
return await self.send_command("get.fan.setting")
|
||||
|
||||
async def set_system_reboot(self) -> dict | None:
|
||||
return await self.send_command("set.system.reboot")
|
||||
|
||||
async def set_system_factory_reset(self, *args, **kwargs) -> dict | None:
|
||||
raise NotImplementedError
|
||||
return await self.send_command("set.system.factory_reset")
|
||||
|
||||
async def set_system_update_firmware(self, *args, **kwargs) -> dict | None:
|
||||
raise NotImplementedError
|
||||
return await self.send_command("set.system.update_firmware")
|
||||
|
||||
async def set_system_net_config(self, *args, **kwargs) -> dict | None:
|
||||
raise NotImplementedError
|
||||
return await self.send_command("set.system.net_config")
|
||||
|
||||
async def set_system_led(self, leds: list | None = None) -> dict | None:
|
||||
if leds is None:
|
||||
return await self.send_command("set.system.led", parameters="auto")
|
||||
else:
|
||||
return await self.send_command("set.system.led", parameters=leds)
|
||||
|
||||
async def set_system_time_randomized(self, *args, **kwargs) -> dict | None:
|
||||
raise NotImplementedError
|
||||
return await self.send_command("set.system.time_randomized")
|
||||
|
||||
async def set_system_timezone(self, *args, **kwargs) -> dict | None:
|
||||
raise NotImplementedError
|
||||
return await self.send_command("set.system.timezone")
|
||||
|
||||
async def set_system_hostname(self, *args, **kwargs) -> dict | None:
|
||||
raise NotImplementedError
|
||||
return await self.send_command("set.system.hostname")
|
||||
|
||||
async def set_system_webpools(self, *args, **kwargs) -> dict | None:
|
||||
raise NotImplementedError
|
||||
return await self.send_command("set.system.webpools")
|
||||
|
||||
async def set_miner_target_freq(self, *args, **kwargs) -> dict | None:
|
||||
raise NotImplementedError
|
||||
return await self.send_command("set.miner.target_freq")
|
||||
|
||||
async def set_miner_heat_mode(self, *args, **kwargs) -> dict | None:
|
||||
raise NotImplementedError
|
||||
return await self.send_command("set.miner.heat_mode")
|
||||
|
||||
async def set_system_ntp_server(self, *args, **kwargs) -> dict | None:
|
||||
raise NotImplementedError
|
||||
return await self.send_command("set.system.ntp_server")
|
||||
|
||||
async def set_miner_service(self, value: str) -> dict | None:
|
||||
return await self.send_command("set.miner.service", parameters=value)
|
||||
|
||||
async def set_miner_power_mode(self, *args, **kwargs) -> dict | None:
|
||||
raise NotImplementedError
|
||||
return await self.send_command("set.miner.power_mode")
|
||||
|
||||
async def set_miner_cointype(self, *args, **kwargs) -> dict | None:
|
||||
raise NotImplementedError
|
||||
return await self.send_command("set.miner.cointype")
|
||||
|
||||
async def set_miner_pools(self, *args, **kwargs) -> dict | None:
|
||||
raise NotImplementedError
|
||||
return await self.send_command("set.miner.pools")
|
||||
|
||||
async def set_miner_fastboot(self, *args, **kwargs) -> dict | None:
|
||||
raise NotImplementedError
|
||||
return await self.send_command("set.miner.fastboot")
|
||||
|
||||
async def set_miner_power_percent(self, *args, **kwargs) -> dict | None:
|
||||
raise NotImplementedError
|
||||
return await self.send_command("set.miner.power_percent")
|
||||
|
||||
async def set_miner_pre_power_on(self, *args, **kwargs) -> dict | None:
|
||||
raise NotImplementedError
|
||||
return await self.send_command("set.miner.pre_power_on")
|
||||
|
||||
async def set_miner_restore_setting(self, *args, **kwargs) -> dict | None:
|
||||
raise NotImplementedError
|
||||
return await self.send_command("set.miner.restore_setting")
|
||||
|
||||
async def set_miner_report(self, frequency: int = 1) -> dict | None:
|
||||
return await self.send_command(
|
||||
"set.miner.report", parameters={"gap": frequency}
|
||||
)
|
||||
|
||||
async def set_miner_power_limit(self, power: int) -> dict | None:
|
||||
return await self.send_command("set.miner.power_limit", parameters=power)
|
||||
|
||||
async def set_miner_upfreq_speed(self, *args, **kwargs) -> dict | None:
|
||||
raise NotImplementedError
|
||||
return await self.send_command("set.miner.upfreq_speed")
|
||||
|
||||
async def set_log_upload(self, *args, **kwargs) -> dict | None:
|
||||
raise NotImplementedError
|
||||
return await self.send_command("set.log.upload")
|
||||
|
||||
async def set_user_change_passwd(self, *args, **kwargs) -> dict | None:
|
||||
raise NotImplementedError
|
||||
return await self.send_command("set.user.change_passwd")
|
||||
|
||||
async def set_user_permission(self, *args, **kwargs) -> dict | None:
|
||||
raise NotImplementedError
|
||||
return await self.send_command("set.user.permission")
|
||||
|
||||
async def set_fan_temp_offset(self, *args, **kwargs) -> dict | None:
|
||||
raise NotImplementedError
|
||||
return await self.send_command("set.fan.temp_offset")
|
||||
|
||||
async def set_fan_poweroff_cool(self, *args, **kwargs) -> dict | None:
|
||||
raise NotImplementedError
|
||||
return await self.send_command("set.fan.poweroff_cool")
|
||||
|
||||
async def set_fan_zero_speed(self, *args, **kwargs) -> dict | None:
|
||||
raise NotImplementedError
|
||||
return await self.send_command("set.fan.zero_speed")
|
||||
|
||||
async def set_shell_debug(self, *args, **kwargs) -> dict | None:
|
||||
raise NotImplementedError
|
||||
return await self.send_command("set.shell.debug")
|
||||
|
||||
@@ -62,7 +62,6 @@ class AntminerModernWebAPI(BaseWebAPI):
|
||||
auth = httpx.DigestAuth(self.username, self.pwd)
|
||||
try:
|
||||
async with httpx.AsyncClient(transport=settings.transport()) as client:
|
||||
|
||||
if parameters:
|
||||
data = await client.post(
|
||||
url,
|
||||
|
||||
@@ -141,17 +141,16 @@ class AuradineWebAPI(BaseWebAPI):
|
||||
self.send_command(cmd, allow_warning=allow_warning)
|
||||
)
|
||||
|
||||
await asyncio.gather(*[tasks[cmd] for cmd in tasks], return_exceptions=True)
|
||||
results = await asyncio.gather(
|
||||
*[tasks[cmd] for cmd in tasks], return_exceptions=True
|
||||
)
|
||||
|
||||
data = {"multicommand": True}
|
||||
for cmd in tasks:
|
||||
try:
|
||||
result = tasks[cmd].result()
|
||||
for cmd, result in zip(tasks.keys(), results):
|
||||
if not isinstance(result, (APIError, Exception)):
|
||||
if result is None or result == {}:
|
||||
result = {}
|
||||
data[cmd] = result
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
return data
|
||||
|
||||
|
||||
@@ -84,13 +84,13 @@ class BOSerWebAPI(BaseWebAPI):
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
await asyncio.gather(*[t for t in tasks.values()], return_exceptions=True)
|
||||
results = await asyncio.gather(
|
||||
*[t for t in tasks.values()], return_exceptions=True
|
||||
)
|
||||
|
||||
for cmd in tasks:
|
||||
try:
|
||||
result[cmd] = await tasks[cmd]
|
||||
except (GRPCError, APIError, ConnectionError):
|
||||
pass
|
||||
for cmd, task_result in zip(tasks.keys(), results):
|
||||
if not isinstance(task_result, (GRPCError, APIError, ConnectionError)):
|
||||
result[cmd] = task_result
|
||||
|
||||
return result
|
||||
|
||||
|
||||
@@ -52,7 +52,6 @@ class ApiVersionServiceStub(betterproto.ServiceStub):
|
||||
|
||||
|
||||
class ApiVersionServiceBase(ServiceBase):
|
||||
|
||||
async def get_api_version(
|
||||
self, api_version_request: "ApiVersionRequest"
|
||||
) -> "ApiVersion":
|
||||
|
||||
@@ -2485,7 +2485,6 @@ class NetworkServiceStub(betterproto.ServiceStub):
|
||||
|
||||
|
||||
class ActionsServiceBase(ServiceBase):
|
||||
|
||||
async def start(self, start_request: "StartRequest") -> "StartResponse":
|
||||
raise grpclib.GRPCError(grpclib.const.Status.UNIMPLEMENTED)
|
||||
|
||||
@@ -2630,7 +2629,6 @@ class ActionsServiceBase(ServiceBase):
|
||||
|
||||
|
||||
class AuthenticationServiceBase(ServiceBase):
|
||||
|
||||
async def login(self, login_request: "LoginRequest") -> "LoginResponse":
|
||||
raise grpclib.GRPCError(grpclib.const.Status.UNIMPLEMENTED)
|
||||
|
||||
@@ -2671,7 +2669,6 @@ class AuthenticationServiceBase(ServiceBase):
|
||||
|
||||
|
||||
class CoolingServiceBase(ServiceBase):
|
||||
|
||||
async def get_cooling_state(
|
||||
self, get_cooling_state_request: "GetCoolingStateRequest"
|
||||
) -> "GetCoolingStateResponse":
|
||||
@@ -2716,7 +2713,6 @@ class CoolingServiceBase(ServiceBase):
|
||||
|
||||
|
||||
class PerformanceServiceBase(ServiceBase):
|
||||
|
||||
async def get_tuner_state(
|
||||
self, get_tuner_state_request: "GetTunerStateRequest"
|
||||
) -> "GetTunerStateResponse":
|
||||
@@ -2986,7 +2982,6 @@ class PerformanceServiceBase(ServiceBase):
|
||||
|
||||
|
||||
class PoolServiceBase(ServiceBase):
|
||||
|
||||
async def get_pool_groups(
|
||||
self, get_pool_groups_request: "GetPoolGroupsRequest"
|
||||
) -> "GetPoolGroupsResponse":
|
||||
@@ -3088,7 +3083,6 @@ class PoolServiceBase(ServiceBase):
|
||||
|
||||
|
||||
class ConfigurationServiceBase(ServiceBase):
|
||||
|
||||
async def get_miner_configuration(
|
||||
self, get_miner_configuration_request: "GetMinerConfigurationRequest"
|
||||
) -> "GetMinerConfigurationResponse":
|
||||
@@ -3133,7 +3127,6 @@ class ConfigurationServiceBase(ServiceBase):
|
||||
|
||||
|
||||
class LicenseServiceBase(ServiceBase):
|
||||
|
||||
async def get_license_state(
|
||||
self, get_license_state_request: "GetLicenseStateRequest"
|
||||
) -> "GetLicenseStateResponse":
|
||||
@@ -3159,7 +3152,6 @@ class LicenseServiceBase(ServiceBase):
|
||||
|
||||
|
||||
class MinerServiceBase(ServiceBase):
|
||||
|
||||
async def get_miner_status(
|
||||
self, get_miner_status_request: "GetMinerStatusRequest"
|
||||
) -> AsyncIterator[GetMinerStatusResponse]:
|
||||
@@ -3325,7 +3317,6 @@ class MinerServiceBase(ServiceBase):
|
||||
|
||||
|
||||
class NetworkServiceBase(ServiceBase):
|
||||
|
||||
async def get_network_configuration(
|
||||
self, get_network_configuration_request: "GetNetworkConfigurationRequest"
|
||||
) -> "GetNetworkConfigurationResponse":
|
||||
|
||||
@@ -60,7 +60,6 @@ class ElphapexWebAPI(BaseWebAPI):
|
||||
auth = httpx.DigestAuth(self.username, self.pwd)
|
||||
try:
|
||||
async with httpx.AsyncClient(transport=settings.transport()) as client:
|
||||
|
||||
if parameters:
|
||||
data = await client.post(
|
||||
url,
|
||||
@@ -121,18 +120,28 @@ class ElphapexWebAPI(BaseWebAPI):
|
||||
"""
|
||||
auth = httpx.DigestAuth(self.username, self.pwd)
|
||||
|
||||
try:
|
||||
url = f"http://{self.ip}/cgi-bin/{command}.cgi"
|
||||
ret = await client.get(url, auth=auth)
|
||||
except httpx.HTTPError:
|
||||
pass
|
||||
else:
|
||||
if ret.status_code == 200:
|
||||
try:
|
||||
json_data = ret.json()
|
||||
return {command: json_data}
|
||||
except json.decoder.JSONDecodeError:
|
||||
pass
|
||||
async def _send():
|
||||
try:
|
||||
url = f"http://{self.ip}/cgi-bin/{command}.cgi"
|
||||
ret = await client.get(url, auth=auth)
|
||||
except httpx.HTTPError:
|
||||
pass
|
||||
else:
|
||||
if ret.status_code == 200:
|
||||
try:
|
||||
json_data = ret.json()
|
||||
if json_data.get("STATUS", {}).get("STATUS") not in ["S", "I"]:
|
||||
return None
|
||||
return {command: json_data}
|
||||
except json.decoder.JSONDecodeError:
|
||||
pass
|
||||
return None
|
||||
|
||||
# retry 3 times
|
||||
for i in range(3):
|
||||
res = await _send()
|
||||
if res is not None:
|
||||
return res
|
||||
return {command: {}}
|
||||
|
||||
async def get_miner_conf(self) -> dict:
|
||||
|
||||
@@ -71,17 +71,16 @@ class ESPMinerWebAPI(BaseWebAPI):
|
||||
self.send_command(cmd, allow_warning=allow_warning)
|
||||
)
|
||||
|
||||
await asyncio.gather(*[tasks[cmd] for cmd in tasks], return_exceptions=True)
|
||||
results = await asyncio.gather(
|
||||
*[tasks[cmd] for cmd in tasks], return_exceptions=True
|
||||
)
|
||||
|
||||
data = {"multicommand": True}
|
||||
for cmd in tasks:
|
||||
try:
|
||||
result = tasks[cmd].result()
|
||||
for cmd, result in zip(tasks.keys(), results):
|
||||
if not isinstance(result, (APIError, Exception)):
|
||||
if result is None or result == {}:
|
||||
result = {}
|
||||
data[cmd] = result
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
return data
|
||||
|
||||
|
||||
@@ -103,8 +103,12 @@ class GoldshellWebAPI(BaseWebAPI):
|
||||
async with httpx.AsyncClient(transport=settings.transport()) as client:
|
||||
for command in commands:
|
||||
try:
|
||||
uri_commnand = command
|
||||
if command == "devs":
|
||||
uri_commnand = "cgminer?cgminercmd=devs"
|
||||
|
||||
response = await client.get(
|
||||
f"http://{self.ip}:{self.port}/mcb/{command}",
|
||||
f"http://{self.ip}:{self.port}/mcb/{uri_commnand}",
|
||||
headers={"Authorization": "Bearer " + self.token},
|
||||
timeout=settings.get("api_function_timeout", 5),
|
||||
)
|
||||
@@ -143,3 +147,6 @@ class GoldshellWebAPI(BaseWebAPI):
|
||||
|
||||
async def status(self) -> dict:
|
||||
return await self.send_command("status")
|
||||
|
||||
async def devs(self) -> dict:
|
||||
return await self.send_command("cgminer?cgminercmd=devs")
|
||||
|
||||
@@ -60,7 +60,6 @@ class HammerWebAPI(BaseWebAPI):
|
||||
auth = httpx.DigestAuth(self.username, self.pwd)
|
||||
try:
|
||||
async with httpx.AsyncClient(transport=settings.transport()) as client:
|
||||
|
||||
if parameters:
|
||||
data = await client.post(
|
||||
url,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "pyasic"
|
||||
version = "0.74.1"
|
||||
version = "0.76.9"
|
||||
|
||||
description = "A simplified and standardized interface for Bitcoin ASICs."
|
||||
authors = [{name = "UpstreamData", email = "brett@upstreamdata.ca"}]
|
||||
@@ -52,6 +52,7 @@ dependencies = [
|
||||
"aiofiles>=23.2.1",
|
||||
"betterproto==2.0.0b7",
|
||||
"pydantic>=2.11.0",
|
||||
"semver (>=3.0.4,<4.0.0)",
|
||||
]
|
||||
|
||||
[tool.poetry.group.dev]
|
||||
|
||||
@@ -33,10 +33,7 @@ class MinersTest(unittest.TestCase):
|
||||
miner_type=miner_type,
|
||||
miner_model=miner_model,
|
||||
):
|
||||
miner = MINER_CLASSES[miner_type][miner_model]("127.0.0.1")
|
||||
self.assertTrue(
|
||||
isinstance(miner, MINER_CLASSES[miner_type][miner_model])
|
||||
)
|
||||
MINER_CLASSES[miner_type][miner_model]("127.0.0.1")
|
||||
|
||||
def test_miner_has_hashboards(self):
|
||||
warnings.filterwarnings("ignore")
|
||||
|
||||
Reference in New Issue
Block a user