Compare commits

...

12 Commits

Author SHA1 Message Date
UpstreamData
98a94ce4a6 bump version number 2022-09-28 10:06:53 -06:00
UpstreamData
f0a8b6e1c7 add support for whatsminer M31S+ V30 2022-09-28 10:05:28 -06:00
UpstreamData
e07bd3bffb bump version number 2022-09-26 13:08:27 -06:00
UpstreamData
dcce944390 Fix a bug where older version of bosminer return excessive hashboard error information 2022-09-26 12:27:37 -06:00
UpstreamData
03ecd118a3 add support for M31S+ V60 and V90 2022-09-26 11:51:47 -06:00
UpstreamData
97c0331762 bump version number 2022-09-26 11:33:42 -06:00
UpstreamData
eda9804dea add support for some new whatsminers types, M31S+ v40 and v80, and improve documentation of supported types. 2022-09-26 11:32:55 -06:00
UpstreamData
e94c81ce44 improve miner network functionality 2022-09-26 09:15:37 -06:00
UpstreamData
c95c58138e bump version number 2022-09-22 10:07:31 -06:00
UpstreamData
03c93b4de1 added pause_mining and resume_mining to all miners, added get_errors to whatsminers, and improved get_errors type hinting 2022-09-22 10:06:27 -06:00
UpstreamData
ff0d15c365 bump version number 2022-09-22 09:06:51 -06:00
UpstreamData
eadcb76d31 add stop_mining and resume_mining for X19 devices 2022-09-22 09:06:22 -06:00
25 changed files with 539 additions and 126 deletions

View File

@@ -118,6 +118,8 @@ These functions are
[`get_model`](#get-model), [`get_model`](#get-model),
[`reboot`](#reboot), [`reboot`](#reboot),
[`restart_backend`](#restart-backend), and [`restart_backend`](#restart-backend), and
[`stop_mining`](#stop-mining), and
[`resume_mining`](#resume-mining), and
[`send_config`](#send-config). [`send_config`](#send-config).
<br> <br>
@@ -202,6 +204,22 @@ These functions are
<br> <br>
### Stop Mining
::: pyasic.miners.BaseMiner.stop_mining
handler: python
options:
heading_level: 4
<br>
### Resume Mining
::: pyasic.miners.BaseMiner.resume_mining
handler: python
options:
heading_level: 4
<br>
### Send Config ### Send Config
::: pyasic.miners.BaseMiner.send_config ::: pyasic.miners.BaseMiner.send_config
handler: python handler: python

View File

@@ -4,93 +4,212 @@
Supported miner types are here on this list. If your miner (or miner version) is not on this list, please feel free to [open an issue on GitHub](https://github.com/UpstreamData/pyasic/issues) to get it added. Supported miner types are here on this list. If your miner (or miner version) is not on this list, please feel free to [open an issue on GitHub](https://github.com/UpstreamData/pyasic/issues) to get it added.
##### pyasic currently supports the following miners and subtypes: ##### pyasic currently supports the following miners and subtypes:
* Braiins OS+ Devices: <details>
* X19 Series: <summary>Braiins OS+ Devices:</summary>
* [S19][pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19] <ul>
* [S19 Pro][pyasic.miners.antminer.bosminer.X19.S19_Pro.BOSMinerS19Pro] <details>
* [S19j][pyasic.miners.antminer.bosminer.X19.S19j.BOSMinerS19j] <summary>X19 Series:</summary>
* [S19j Pro][pyasic.miners.antminer.bosminer.X19.S19j_Pro.BOSMinerS19jPro] <ul>
* [T19][pyasic.miners.antminer.bosminer.X19.T19.BOSMinerT19] <li><a href="/miners/antminer/X19#s19-bos">S19</a></li>
* X17 Series: <li><a href="/miners/antminer/X19#s19-pro-bos">S19 Pro</a></li>
* [S17][pyasic.miners.antminer.bosminer.X17.S17.BOSMinerS17] <li><a href="/miners/antminer/X19#s19j-bos">S19j</a></li>
* [S17+][pyasic.miners.antminer.bosminer.X17.S17_Plus.BOSMinerS17Plus] <li><a href="/miners/antminer/X19#s19j-pro-bos">S19j Pro</a></li>
* [S17 Pro][pyasic.miners.antminer.bosminer.X17.S17_Pro.BOSMinerS17Pro] <li><a href="/miners/antminer/X19#t19-bos">T19</a></li>
* [S17e][pyasic.miners.antminer.bosminer.X17.S17e.BOSMinerS17e] </ul>
* [T17][pyasic.miners.antminer.bosminer.X17.T17.BOSMinerT17] </details>
* [T17+][pyasic.miners.antminer.bosminer.X17.T17_Plus.BOSMinerT17Plus] <details>
* [T17e][pyasic.miners.antminer.bosminer.X17.T17e.BOSMinerT17e] <summary>X17 Series:</summary>
* X9 Series: <ul>
* [S9][pyasic.miners.antminer.bosminer.X9.S9.BOSMinerS9] <li><a href="/miners/antminer/X17#s17-bos">S17</a></li>
* [S9i][pyasic.miners.antminer.bosminer.X9.S9.BOSMinerS9] <li><a href="/miners/antminer/X17#s17-plus-bos">S17+</a></li>
* [S9j][pyasic.miners.antminer.bosminer.X9.S9.BOSMinerS9] <li><a href="/miners/antminer/X17#s17-pro-bos">S17 Pro</a></li>
* Stock Firmware Whatsminers: <li><a href="/miners/antminer/X17#s17e-bos">S17e</a></li>
* M3X Series: <li><a href="/miners/antminer/X17#t17-bos">T17</a></li>
* [M30S][pyasic.miners.whatsminer.btminer.M3X.M30S.BTMinerM30S]: <li><a href="/miners/antminer/X17#t17-plus-bos">T17+</a></li>
* [VE10][pyasic.miners.whatsminer.btminer.M3X.M30S.BTMinerM30SVE10] <li><a href="/miners/antminer/X17#t17e-bos">T17e</a></li>
* [VG20][pyasic.miners.whatsminer.btminer.M3X.M30S.BTMinerM30SVG20] </ul>
* [VE20][pyasic.miners.whatsminer.btminer.M3X.M30S.BTMinerM30SVE20] </details>
* [V50][pyasic.miners.whatsminer.btminer.M3X.M30S.BTMinerM30SV50] <details>
* [M30S+][pyasic.miners.whatsminer.btminer.M3X.M30S_Plus.BTMinerM30SPlus]: <summary>X9 Series:</summary>
* [VF20][pyasic.miners.whatsminer.btminer.M3X.M30S_Plus.BTMinerM30SPlusVF20] <ul>
* [VE40][pyasic.miners.whatsminer.btminer.M3X.M30S_Plus.BTMinerM30SPlusVE40] <li><a href="/miners/antminer/X9#s9-bos">S9</a></li>
* [VG60][pyasic.miners.whatsminer.btminer.M3X.M30S_Plus.BTMinerM30SPlusVG60] <li><a href="/miners/antminer/X9#s9-bos">S9i</a></li>
* [M30S++][pyasic.miners.whatsminer.btminer.M3X.M30S_Plus_Plus.BTMinerM30SPlusPlus]: <li><a href="/miners/antminer/X9#s9-bos">S9j</a></li>
* [VG30][pyasic.miners.whatsminer.btminer.M3X.M30S_Plus_Plus.BTMinerM30SPlusPlusVG30] </ul>
* [VG40][pyasic.miners.whatsminer.btminer.M3X.M30S_Plus_Plus.BTMinerM30SPlusPlusVG40] </details>
* [VH60][pyasic.miners.whatsminer.btminer.M3X.M30S_Plus_Plus.BTMinerM30SPlusPlusVH60] </ul>
* [M31S][pyasic.miners.whatsminer.btminer.M3X.M31S.BTMinerM31S] </details>
* [M31S+][pyasic.miners.whatsminer.btminer.M3X.M31S_Plus.BTMinerM31SPlus]: <details>
* [VE20][pyasic.miners.whatsminer.btminer.M3X.M31S_Plus.BTMinerM31SPlusVE20] <summary>Stock Firmware Whatsminers:</summary>
* [M32][pyasic.miners.whatsminer.btminer.M3X.M32.BTMinerM32] <ul>
* [V20][pyasic.miners.whatsminer.btminer.M3X.M32.BTMinerM32V20] <details>
* [M32S][pyasic.miners.whatsminer.btminer.M3X.M32S.BTMinerM32S] <summary>M3X Series:</summary>
* M2X Series: <ul>
* [M20][pyasic.miners.whatsminer.btminer.M2X.M20.BTMinerM20]: <details>
* [V10][pyasic.miners.whatsminer.btminer.M2X.M20.BTMinerM20V10] <summary><a href="/miners/whatsminer/M3X/#m30s">M30S</a></summary>
* [M20S][pyasic.miners.whatsminer.btminer.M2X.M20S.BTMinerM20S]: <ul>
* [V10][pyasic.miners.whatsminer.btminer.M2X.M20S.BTMinerM20SV10] <li><a href="/miners/whatsminer/M3X/#m30sve10">VE10</a></li>
* [V20][pyasic.miners.whatsminer.btminer.M2X.M20S.BTMinerM20SV20] <li><a href="/miners/whatsminer/M3X/#m30svg20">VG20</a></li>
* [M20S+][pyasic.miners.whatsminer.btminer.M2X.M20S_Plus.BTMinerM20SPlus] <li><a href="/miners/whatsminer/M3X/#m30sve20">VE20</a></li>
* [M21][pyasic.miners.whatsminer.btminer.M2X.M21.BTMinerM21] <li><a href="/miners/whatsminer/M3X/#m30sv50">V50</a></li>
* [M21S][pyasic.miners.whatsminer.btminer.M2X.M21S.BTMinerM21S]: </ul>
* [V20][pyasic.miners.whatsminer.btminer.M2X.M21S.BTMinerM21SV20] </details>
* [V60][pyasic.miners.whatsminer.btminer.M2X.M21S.BTMinerM21SV60] <details>
* [M21S+][pyasic.miners.whatsminer.btminer.M2X.M21S_Plus.BTMinerM21SPlus] <summary><a href="/miners/whatsminer/M3X/#m30s_1">M30S+</a></summary>
* Stock Firmware Antminers: <ul>
* X19 Series: <li><a href="/miners/whatsminer/M3X/#m30svf20">VF20</a></li>
* [S19][pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19] <li><a href="/miners/whatsminer/M3X/#m30sve40">VE40</a></li>
* [S19 Pro][pyasic.miners.antminer.bmminer.X19.S19_Pro.BMMinerS19Pro] <li><a href="/miners/whatsminer/M3X/#m30svg60">VG60</a></li>
* [S19a][pyasic.miners.antminer.bmminer.X19.S19a.BMMinerS19a] </ul>
* [S19j][pyasic.miners.antminer.bmminer.X19.S19j.BMMinerS19j] </details>
* [S19j Pro][pyasic.miners.antminer.bmminer.X19.S19j_Pro.BMMinerS19jPro] <details>
* [T19][pyasic.miners.antminer.bmminer.X19.T19.BMMinerT19] <summary><a href="/miners/whatsminer/M3X/#m30s_2">M30S++</a></summary>
* X17 Series: <ul>
* [S17][pyasic.miners.antminer.bmminer.X17.S17.BMMinerS17] <li><a href="/miners/whatsminer/M3X/#m30svg30">VG30</a></li>
* [S17+][pyasic.miners.antminer.bmminer.X17.S17_Plus.BMMinerS17Plus] <li><a href="/miners/whatsminer/M3X/#m30svg40">VG40</a></li>
* [S17 Pro][pyasic.miners.antminer.bmminer.X17.S17_Pro.BMMinerS17Pro] <li><a href="/miners/whatsminer/M3X/#m30svh60">VH60</a></li>
* [S17e][pyasic.miners.antminer.bmminer.X17.S17e.BMMinerS17e] </ul>
* [T17][pyasic.miners.antminer.bmminer.X17.T17.BMMinerT17] </details>
* [T17+][pyasic.miners.antminer.bmminer.X17.T17_Plus.BMMinerT17Plus] <details>
* [T17e][pyasic.miners.antminer.bmminer.X17.T17e.BMMinerT17e] <summary><a href="/miners/whatsminer/M3X/#m31s">M31S</a></summary>
* X9 Series: </details>
* [S9][pyasic.miners.antminer.bmminer.X9.S9.BMMinerS9] <details>
* [S9i][pyasic.miners.antminer.bmminer.X9.S9i.BMMinerS9i] <summary><a href="/miners/whatsminer/M3X/#m31s_1">M31S+</a></summary>
* [T9][pyasic.miners.antminer.bmminer.X9.T9.BMMinerT9] <ul>
* Stock Firmware Avalonminers: <li><a href="/miners/whatsminer/M3X/#m31sve20">VE20</a></li>
* A7X Series: <li><a href="/miners/whatsminer/M3X/#m31sv30">V30</a></li>
* [A721][pyasic.miners.avalonminer.cgminer.A7X.A721.CGMinerAvalon721] <li><a href="/miners/whatsminer/M3X/#m31sv40">V40</a></li>
* [A741][pyasic.miners.avalonminer.cgminer.A7X.A741.CGMinerAvalon741] <li><a href="/miners/whatsminer/M3X/#m31sv60">V60</a></li>
* [A761][pyasic.miners.avalonminer.cgminer.A7X.A761.CGMinerAvalon761] <li><a href="/miners/whatsminer/M3X/#m31sv80">V80</a></li>
* A8X Series: <li><a href="/miners/whatsminer/M3X/#m31sv90">V90</a></li>
* [A821][pyasic.miners.avalonminer.cgminer.A8X.A821.CGMinerAvalon821] </ul>
* [A841][pyasic.miners.avalonminer.cgminer.A8X.A841.CGMinerAvalon841] </details>
* [A851][pyasic.miners.avalonminer.cgminer.A8X.A851.CGMinerAvalon851] <details>
* A9X Series: <summary><a href="/miners/whatsminer/M3X/#m32">M32</a></summary>
* [A921][pyasic.miners.avalonminer.cgminer.A9X.A921.CGMinerAvalon921] <ul>
* A10X Series: <li><a href="/miners/whatsminer/M3X/#m32v20">V20</a></li>
* [A1026][pyasic.miners.avalonminer.cgminer.A10X.A1026.CGMinerAvalon1026] </ul>
* [A1047][pyasic.miners.avalonminer.cgminer.A10X.A1047.CGMinerAvalon1047] </details>
* [A1066][pyasic.miners.avalonminer.cgminer.A10X.A1066.CGMinerAvalon1066] <details>
* Stock Firmware Innosilicon Miners: <summary><a href="/miners/whatsminer/M3X/#m32s">M32S</a></summary>
* T3X Series: </details>
* [T3H+][pyasic.miners.innosilicon.cgminer.T3X.T3H_Plus.CGMinerInnosiliconT3HPlus] </ul>
</details>
<details>
<summary>M2X Series:</summary>
<ul>
<details>
<summary><a href="/miners/whatsminer/M2X/#m20">M20</a></summary>
<ul>
<li><a href="/miners/whatsminer/M2X/#m20v10">V10</a></li>
</ul>
</details>
<details>
<summary><a href="/miners/whatsminer/M2X/#m20s">M20S</a></summary>
<ul>
<li><a href="/miners/whatsminer/M2X/#m20sv10">V10</a></li>
<li><a href="/miners/whatsminer/M2X/#m20sv20">V20</a></li>
</ul>
</details>
<details>
<summary><a href="/miners/whatsminer/M2X/#m20s_1">M20S+</a></summary>
</details>
<details>
<summary><a href="/miners/whatsminer/M2X/#m21">M21</a></summary>
</details>
<details>
<summary><a href="/miners/whatsminer/M2X/#m21s">M21S</a></summary>
<ul>
<li><a href="/miners/whatsminer/M2X/#m21sv20">V20</a></li>
<li><a href="/miners/whatsminer/M2X/#m21sv60">V60</a></li>
</ul>
</details>
<details>
<summary><a href="/miners/whatsminer/M2X/#m21s_1">M21S+</a></summary>
</details>
</ul>
</details>
</ul>
</details>
<details>
<summary>Stock Firmware Antminers:</summary>
<ul>
<details>
<summary>X19 Series:</summary>
<ul>
<li><a href="/miners/antminer/X19/#s19">S19</a></li>
<li><a href="/miners/antminer/X19/#s19-pro">S19 Pro</a></li>
<li><a href="/miners/antminer/X19/#s19a">S19a</a></li>
<li><a href="/miners/antminer/X19/#s19j">S19j</a></li>
<li><a href="/miners/antminer/X19/#s19j-pro">S19j Pro</a></li>
<li><a href="/miners/antminer/X19/#t19">T19</a></li>
</ul>
</details>
<details>
<summary>X17 Series:</summary>
<ul>
<li><a href="/miners/antminer/X17/#s17">S17</a></li>
<li><a href="/miners/antminer/X17/#s17_1">S17+</a></li>
<li><a href="/miners/antminer/X17/#s17-pro">S17 Pro</a></li>
<li><a href="/miners/antminer/X17/#s17e">S17e</a></li>
<li><a href="/miners/antminer/X17/#t17">T17</a></li>
<li><a href="/miners/antminer/X17/#t17_1">T17+</a></li>
<li><a href="/miners/antminer/X17/#t17e">T17e</a></li>
</ul>
</details>
<details>
<summary>X9 Series:</summary>
<ul>
<li><a href="/miners/antminer/X9/#s9">S9</a></li>
<li><a href="/miners/antminer/X9/#s9i">S9i</a></li>
<li><a href="/miners/antminer/X9/#t9">T9</a></li>
</ul>
</details>
</ul>
</details>
<details>
<summary>Stock Firmware Avalonminers:</summary>
<ul>
<details>
<summary>A7X Series:</summary>
<ul>
<li><a href="/miners/avalonminer/A7X/#a721">A721</a></li>
<li><a href="/miners/avalonminer/A7X/#a741">A741</a></li>
<li><a href="/miners/avalonminer/A7X/#a761">A761</a></li>
</ul>
</details>
<details>
<summary>A8X Series:</summary>
<ul>
<li><a href="/miners/avalonminer/A8X/#a821">A821</a></li>
<li><a href="/miners/avalonminer/A8X/#a841">A841</a></li>
<li><a href="/miners/avalonminer/A8X/#a851">A851</a></li>
</ul>
</details>
<details>
<summary>A9X Series:</summary>
<ul>
<li><a href="/miners/avalonminer/A9X/#a921">A921</a></li>
</ul>
</details>
<details>
<summary>A10X Series:</summary>
<ul>
<li><a href="/miners/avalonminer/A10X/#a1026">A1026</a></li>
<li><a href="/miners/avalonminer/A10X/#a1047">A1047</a></li>
<li><a href="/miners/avalonminer/A10X/#a1066">A1066</a></li>
</ul>
</details>
</ul>
</details>
<details>
<summary>Stock Firmware Innosilicon Miners:</summary>
<ul>
<details>
<summary>T3X Series:</summary>
<ul>
<li><a href="/miners/innosilicon/T3X/#t3h">T3H+</a></li>
</ul>
</details>
</ul>
</details>

View File

@@ -130,6 +130,46 @@
show_root_heading: false show_root_heading: false
heading_level: 4 heading_level: 4
## M31S+V30
::: pyasic.miners.whatsminer.btminer.M3X.M31S_Plus.BTMinerM31SPlusV30
handler: python
options:
show_root_heading: false
heading_level: 4
## M31S+V40
::: pyasic.miners.whatsminer.btminer.M3X.M31S_Plus.BTMinerM31SPlusV40
handler: python
options:
show_root_heading: false
heading_level: 4
## M31S+V60
::: pyasic.miners.whatsminer.btminer.M3X.M31S_Plus.BTMinerM31SPlusV60
handler: python
options:
show_root_heading: false
heading_level: 4
## M31S+V80
::: pyasic.miners.whatsminer.btminer.M3X.M31S_Plus.BTMinerM31SPlusV80
handler: python
options:
show_root_heading: false
heading_level: 4
## M31S+V90
::: pyasic.miners.whatsminer.btminer.M3X.M31S_Plus.BTMinerM31SPlusV90
handler: python
options:
show_root_heading: false
heading_level: 4
## M32 ## M32
::: pyasic.miners.whatsminer.btminer.M3X.M32.BTMinerM32 ::: pyasic.miners.whatsminer.btminer.M3X.M32.BTMinerM32

View File

@@ -299,6 +299,10 @@ class MinerConfig:
self.temp_mode = "manual" self.temp_mode = "manual"
if data.get("bitmain-fan-pwm"): if data.get("bitmain-fan-pwm"):
self.fan_speed = int(data["bitmain-fan-pwm"]) self.fan_speed = int(data["bitmain-fan-pwm"])
elif key == "bitmain-work-mode":
if data[key]:
if data[key] == 1:
self.autotuning_wattage = 0
elif key == "fan_control": elif key == "fan_control":
for _key in data[key].keys(): for _key in data[key].keys():
if _key == "min_fans": if _key == "min_fans":
@@ -409,7 +413,10 @@ class MinerConfig:
"pools": self.pool_groups[0].as_x19(user_suffix=user_suffix), "pools": self.pool_groups[0].as_x19(user_suffix=user_suffix),
"bitmain-fan-ctrl": False, "bitmain-fan-ctrl": False,
"bitmain-fan-pwn": 100, "bitmain-fan-pwn": 100,
"miner-mode": 0, # Normal Mode
} }
if self.autotuning_wattage == 0:
cfg["miner-mode"] = 1 # Sleep Mode
if not self.temp_mode == "auto": if not self.temp_mode == "auto":
cfg["bitmain-fan-ctrl"] = True cfg["bitmain-fan-ctrl"] = True

View File

@@ -16,3 +16,9 @@ from .whatsminer import WhatsminerError
from .bos import BraiinsOSError from .bos import BraiinsOSError
from .X19 import X19Error from .X19 import X19Error
from .innosilicon import InnosiliconError from .innosilicon import InnosiliconError
from typing import TypeVar
MinerErrorData = TypeVar(
"MinerErrorData", WhatsminerError, BraiinsOSError, X19Error, InnosiliconError
)

View File

@@ -14,7 +14,7 @@
import ipaddress import ipaddress
import logging import logging
from typing import Union from typing import Union, List
from pyasic.API.bmminer import BMMinerAPI from pyasic.API.bmminer import BMMinerAPI
@@ -22,6 +22,7 @@ from pyasic.miners.base import BaseMiner
from pyasic.data import MinerData from pyasic.data import MinerData
from pyasic.config import MinerConfig from pyasic.config import MinerConfig
from pyasic.data.error_codes import MinerErrorData
from pyasic.settings import PyasicSettings from pyasic.settings import PyasicSettings
@@ -169,7 +170,7 @@ class BMMiner(BaseMiner):
async def fault_light_on(self) -> bool: async def fault_light_on(self) -> bool:
return False return False
async def get_errors(self) -> list: async def get_errors(self) -> List[MinerErrorData]:
return [] return []
async def get_mac(self) -> str: async def get_mac(self) -> str:
@@ -178,6 +179,12 @@ class BMMiner(BaseMiner):
async def restart_backend(self) -> bool: async def restart_backend(self) -> bool:
return False return False
async def stop_mining(self) -> bool:
return False
async def resume_mining(self) -> bool:
return False
async def get_data(self) -> MinerData: async def get_data(self) -> MinerData:
"""Get data from the miner. """Get data from the miner.

View File

@@ -15,7 +15,7 @@
import ipaddress import ipaddress
import logging import logging
import json import json
from typing import Union from typing import Union, List
import toml import toml
@@ -24,7 +24,7 @@ from pyasic.miners.base import BaseMiner
from pyasic.API.bosminer import BOSMinerAPI from pyasic.API.bosminer import BOSMinerAPI
from pyasic.errors import APIError from pyasic.errors import APIError
from pyasic.data.error_codes import BraiinsOSError from pyasic.data.error_codes import BraiinsOSError, MinerErrorData
from pyasic.data import MinerData from pyasic.data import MinerData
from pyasic.config import MinerConfig from pyasic.config import MinerConfig
@@ -103,6 +103,20 @@ class BOSMiner(BaseMiner):
return True return True
return False return False
async def stop_mining(self) -> bool:
data = await self.api.pause()
if data.get("PAUSE"):
if data["PAUSE"][0]:
return True
return False
async def resume_mining(self) -> bool:
data = await self.api.resume()
if data.get("RESUME"):
if data["RESUME"][0]:
return True
return False
async def reboot(self) -> bool: async def reboot(self) -> bool:
"""Reboots power to the physical miner.""" """Reboots power to the physical miner."""
logging.debug(f"{self}: Sending reboot command.") logging.debug(f"{self}: Sending reboot command.")
@@ -242,7 +256,7 @@ class BOSMiner(BaseMiner):
self.light = True self.light = True
return self.light return self.light
async def get_errors(self) -> list: async def get_errors(self) -> List[MinerErrorData]:
tunerstatus = None tunerstatus = None
errors = [] errors = []
@@ -273,7 +287,7 @@ class BOSMiner(BaseMiner):
"Stable", "Stable",
"Testing performance profile", "Testing performance profile",
]: ]:
_error = board["Status"] _error = board["Status"].split(" {")[0]
_error = _error[0].lower() + _error[1:] _error = _error[0].lower() + _error[1:]
errors.append( errors.append(
BraiinsOSError(f"{board_map[_id]} {_error}") BraiinsOSError(f"{board_map[_id]} {_error}")
@@ -437,7 +451,7 @@ class BOSMiner(BaseMiner):
"Stable", "Stable",
"Testing performance profile", "Testing performance profile",
]: ]:
_error = board["Status"] _error = board["Status"].split(" {")[0]
_error = _error[0].lower() + _error[1:] _error = _error[0].lower() + _error[1:]
data.errors.append( data.errors.append(
BraiinsOSError(f"{board_map[_id]} {_error}") BraiinsOSError(f"{board_map[_id]} {_error}")

View File

@@ -15,12 +15,13 @@
import logging import logging
import ipaddress import ipaddress
from typing import Union from typing import Union, List
from pyasic.API.bosminer import BOSMinerAPI from pyasic.API.bosminer import BOSMinerAPI
from pyasic.miners.base import BaseMiner from pyasic.miners.base import BaseMiner
from pyasic.config import MinerConfig from pyasic.config import MinerConfig
from pyasic.data import MinerData from pyasic.data import MinerData
from pyasic.data.error_codes import MinerErrorData
class BOSMinerOld(BaseMiner): class BOSMinerOld(BaseMiner):
@@ -77,7 +78,7 @@ class BOSMinerOld(BaseMiner):
async def get_config(self) -> None: async def get_config(self) -> None:
return None return None
async def get_errors(self) -> list: async def get_errors(self) -> List[MinerErrorData]:
return [] return []
async def get_hostname(self) -> str: async def get_hostname(self) -> str:
@@ -95,6 +96,12 @@ class BOSMinerOld(BaseMiner):
async def restart_backend(self) -> bool: async def restart_backend(self) -> bool:
return False return False
async def stop_mining(self) -> bool:
return False
async def resume_mining(self) -> bool:
return False
async def send_config(self, config: MinerConfig, user_suffix: str = None) -> None: async def send_config(self, config: MinerConfig, user_suffix: str = None) -> None:
return None return None

View File

@@ -14,7 +14,7 @@
import ipaddress import ipaddress
import logging import logging
from typing import Union from typing import Union, List
from pyasic.API.btminer import BTMinerAPI from pyasic.API.btminer import BTMinerAPI
@@ -22,7 +22,7 @@ from pyasic.miners.base import BaseMiner
from pyasic.errors import APIError from pyasic.errors import APIError
from pyasic.data import MinerData from pyasic.data import MinerData
from pyasic.data.error_codes import WhatsminerError from pyasic.data.error_codes import WhatsminerError, MinerErrorData
from pyasic.config import MinerConfig from pyasic.config import MinerConfig
from pyasic.settings import PyasicSettings from pyasic.settings import PyasicSettings
@@ -156,13 +156,44 @@ class BTMiner(BaseMiner):
return True return True
return False return False
async def get_errors(self) -> list: async def get_errors(self) -> List[MinerErrorData]:
return [] data = []
summary_data = await self.api.summary()
if summary_data[0].get("Error Code Count"):
for i in range(summary_data[0]["Error Code Count"]):
if summary_data[0].get(f"Error Code {i}"):
data.append(
WhatsminerError(error_code=summary_data[0][f"Error Code {i}"])
)
return data
async def reboot(self) -> bool: async def reboot(self) -> bool:
data = await self.api.reboot()
if data.get("Msg"):
if data["Msg"] == "API command OK":
return True
return False return False
async def restart_backend(self) -> bool: async def restart_backend(self) -> bool:
data = await self.api.restart()
if data.get("Msg"):
if data["Msg"] == "API command OK":
return True
return False
async def stop_mining(self) -> bool:
data = await self.api.power_off(respbefore=True)
if data.get("Msg"):
if data["Msg"] == "API command OK":
return True
return False
async def resume_mining(self) -> bool:
data = await self.api.power_on()
if data.get("Msg"):
if data["Msg"] == "API command OK":
return True
return False return False
async def send_config(self, config: MinerConfig, user_suffix: str = None) -> None: async def send_config(self, config: MinerConfig, user_suffix: str = None) -> None:

View File

@@ -14,7 +14,7 @@
import ipaddress import ipaddress
import logging import logging
from typing import Union from typing import Union, List
from pyasic.API.cgminer import CGMinerAPI from pyasic.API.cgminer import CGMinerAPI
@@ -23,6 +23,7 @@ from pyasic.errors import APIError
from pyasic.config import MinerConfig from pyasic.config import MinerConfig
from pyasic.data import MinerData from pyasic.data import MinerData
from pyasic.data.error_codes import MinerErrorData
from pyasic.settings import PyasicSettings from pyasic.settings import PyasicSettings
@@ -118,8 +119,7 @@ class CGMiner(BaseMiner):
return True return True
return False return False
async def start_cgminer(self) -> None: async def resume_mining(self) -> bool:
"""Start cgminer hashing process."""
commands = [ commands = [
"mkdir -p /etc/tmp/", "mkdir -p /etc/tmp/",
'echo "*/3 * * * * /usr/bin/cgminer-monitor" > /etc/tmp/root', 'echo "*/3 * * * * /usr/bin/cgminer-monitor" > /etc/tmp/root',
@@ -128,9 +128,9 @@ class CGMiner(BaseMiner):
] ]
commands = ";".join(commands) commands = ";".join(commands)
await self.send_ssh_command(commands) await self.send_ssh_command(commands)
return True
async def stop_cgminer(self) -> None: async def stop_mining(self) -> bool:
"""Restart cgminer hashing process."""
commands = [ commands = [
"mkdir -p /etc/tmp/", "mkdir -p /etc/tmp/",
'echo "" > /etc/tmp/root', 'echo "" > /etc/tmp/root',
@@ -139,6 +139,7 @@ class CGMiner(BaseMiner):
] ]
commands = ";".join(commands) commands = ";".join(commands)
await self.send_ssh_command(commands) await self.send_ssh_command(commands)
return True
async def get_config(self) -> str: async def get_config(self) -> str:
"""Gets the config for the miner and sets it as `self.config`. """Gets the config for the miner and sets it as `self.config`.
@@ -163,7 +164,7 @@ class CGMiner(BaseMiner):
async def fault_light_on(self) -> bool: async def fault_light_on(self) -> bool:
return False return False
async def get_errors(self) -> list: async def get_errors(self) -> List[MinerErrorData]:
return [] return []
async def send_config(self, config: MinerConfig, user_suffix: str = None) -> None: async def send_config(self, config: MinerConfig, user_suffix: str = None) -> None:

View File

@@ -31,3 +31,48 @@ class M31SPlusVE20(BaseMiner):
self.model = "M31S+ VE20" self.model = "M31S+ VE20"
self.nominal_chips = 78 self.nominal_chips = 78
self.fan_count = 2 self.fan_count = 2
class M31SPlusV30(BaseMiner):
def __init__(self, ip: str):
super().__init__()
self.ip = ip
self.model = "M31S+ V30"
self.nominal_chips = 17
self.fan_count = 2
class M31SPlusV40(BaseMiner):
def __init__(self, ip: str):
super().__init__()
self.ip = ip
self.model = "M31S+ V40"
self.nominal_chips = 123
self.fan_count = 2
class M31SPlusV60(BaseMiner):
def __init__(self, ip: str):
super().__init__()
self.ip = ip
self.model = "M31S+ V60"
self.nominal_chips = 156
self.fan_count = 2
class M31SPlusV80(BaseMiner):
def __init__(self, ip: str):
super().__init__()
self.ip = ip
self.model = "M31S+ V80"
self.nominal_chips = 129
self.fan_count = 2
class M31SPlusV90(BaseMiner):
def __init__(self, ip: str):
super().__init__()
self.ip = ip
self.model = "M31S+ V90"
self.nominal_chips = 117
self.fan_count = 2

View File

@@ -22,7 +22,15 @@ from .M30S_Plus_Plus import (
) )
from .M31S import M31S from .M31S import M31S
from .M31S_Plus import M31SPlus, M31SPlusVE20 from .M31S_Plus import (
M31SPlus,
M31SPlusVE20,
M31SPlusV30,
M31SPlusV40,
M31SPlusV80,
M31SPlusV60,
M31SPlusV90,
)
from .M32 import M32, M32V20 from .M32 import M32, M32V20
from .M32S import M32S from .M32S import M32S

View File

@@ -15,7 +15,7 @@
from pyasic.miners._backends import BMMiner # noqa - Ignore access to _module from pyasic.miners._backends import BMMiner # noqa - Ignore access to _module
from pyasic.config import MinerConfig from pyasic.config import MinerConfig
from pyasic.data.error_codes import X19Error from pyasic.data.error_codes import X19Error, MinerErrorData
from pyasic.settings import PyasicSettings from pyasic.settings import PyasicSettings
import httpx import httpx
@@ -132,7 +132,7 @@ class BMMinerX19(BMMiner):
return True return True
return False return False
async def get_errors(self) -> List[X19Error]: async def get_errors(self) -> List[MinerErrorData]:
errors = [] errors = []
url = f"http://{self.ip}/cgi-bin/summary.cgi" url = f"http://{self.ip}/cgi-bin/summary.cgi"
auth = httpx.DigestAuth(self.uname, self.pwd) auth = httpx.DigestAuth(self.uname, self.pwd)
@@ -146,3 +146,15 @@ class BMMinerX19(BMMiner):
if not item["status"] == "s": if not item["status"] == "s":
errors.append(X19Error(item["msg"])) errors.append(X19Error(item["msg"]))
return errors return errors
async def stop_mining(self) -> bool:
cfg = await self.get_config()
cfg.autotuning_wattage = 0
await self.send_config(cfg)
return True
async def resume_mining(self) -> bool:
cfg = await self.get_config()
cfg.autotuning_wattage = 1
await self.send_config(cfg)
return True

View File

@@ -51,6 +51,12 @@ class CGMinerA10X(CGMiner):
return True return True
return False return False
async def stop_mining(self) -> bool:
return False
async def resume_mining(self) -> bool:
return False
async def send_config(self, config: MinerConfig, user_suffix: str = None) -> None: async def send_config(self, config: MinerConfig, user_suffix: str = None) -> None:
"""Configures miner with yaml config.""" """Configures miner with yaml config."""
raise NotImplementedError raise NotImplementedError

View File

@@ -51,6 +51,12 @@ class CGMinerA7X(CGMiner):
return True return True
return False return False
async def stop_mining(self) -> bool:
return False
async def resume_mining(self) -> bool:
return False
async def send_config(self, config: MinerConfig, user_suffix: str = None) -> None: async def send_config(self, config: MinerConfig, user_suffix: str = None) -> None:
"""Configures miner with yaml config.""" """Configures miner with yaml config."""
raise NotImplementedError raise NotImplementedError

View File

@@ -51,6 +51,12 @@ class CGMinerA8X(CGMiner):
return True return True
return False return False
async def stop_mining(self) -> bool:
return False
async def resume_mining(self) -> bool:
return False
async def send_config(self, config: MinerConfig, user_suffix: str = None) -> None: async def send_config(self, config: MinerConfig, user_suffix: str = None) -> None:
"""Configures miner with yaml config.""" """Configures miner with yaml config."""
raise NotImplementedError raise NotImplementedError

View File

@@ -52,6 +52,12 @@ class CGMinerAvalon921(CGMiner, Avalon921):
return True return True
return False return False
async def stop_mining(self) -> bool:
return False
async def resume_mining(self) -> bool:
return False
async def send_config(self, config: MinerConfig, user_suffix: str = None) -> None: async def send_config(self, config: MinerConfig, user_suffix: str = None) -> None:
"""Configures miner with yaml config.""" """Configures miner with yaml config."""
raise NotImplementedError raise NotImplementedError

View File

@@ -25,6 +25,7 @@ from pyasic.data.error_codes import (
BraiinsOSError, BraiinsOSError,
InnosiliconError, InnosiliconError,
X19Error, X19Error,
MinerErrorData,
) )
@@ -181,9 +182,7 @@ class BaseMiner(ABC):
pass pass
@abstractmethod @abstractmethod
async def get_errors( async def get_errors(self) -> List[MinerErrorData]:
self,
) -> List[Union[WhatsminerError, BraiinsOSError, InnosiliconError, X19Error]]:
"""Get a list of the errors the miner is experiencing. """Get a list of the errors the miner is experiencing.
Returns: Returns:
@@ -200,5 +199,23 @@ class BaseMiner(ABC):
""" """
return MinerData(ip=str(self.ip)) return MinerData(ip=str(self.ip))
@abstractmethod
async def stop_mining(self) -> bool:
"""Stop the mining process of the miner.
Returns:
A boolean value of the success of stopping the mining process.
"""
pass
@abstractmethod
async def resume_mining(self) -> bool:
"""Stop the mining process of the miner.
Returns:
A boolean value of the success of resuming the mining process.
"""
pass
AnyMiner = TypeVar("AnyMiner", bound=BaseMiner) AnyMiner = TypeVar("AnyMiner", bound=BaseMiner)

View File

@@ -15,14 +15,14 @@
from pyasic.miners._backends import CGMiner # noqa - Ignore access to _module from pyasic.miners._backends import CGMiner # noqa - Ignore access to _module
from pyasic.miners._types import InnosiliconT3HPlus # noqa - Ignore access to _module from pyasic.miners._types import InnosiliconT3HPlus # noqa - Ignore access to _module
from pyasic.data import MinerData from pyasic.data import MinerData
from pyasic.data.error_codes import InnosiliconError from pyasic.data.error_codes import InnosiliconError, MinerErrorData
from pyasic.settings import PyasicSettings from pyasic.settings import PyasicSettings
from pyasic.config import MinerConfig from pyasic.config import MinerConfig
from pyasic.errors import APIError from pyasic.errors import APIError
import httpx import httpx
import warnings import warnings
from typing import Union from typing import Union, List
import logging import logging
@@ -142,7 +142,7 @@ class CGMinerInnosiliconT3HPlus(CGMiner, InnosiliconT3HPlus):
"updatePools", data=config.as_inno(user_suffix=user_suffix) "updatePools", data=config.as_inno(user_suffix=user_suffix)
) )
async def get_errors(self) -> list: async def get_errors(self) -> List[MinerErrorData]:
errors = [] errors = []
try: try:
data = await self.send_web_command("getErrorDetail") data = await self.send_web_command("getErrorDetail")
@@ -158,11 +158,6 @@ class CGMinerInnosiliconT3HPlus(CGMiner, InnosiliconT3HPlus):
return errors return errors
async def get_data(self) -> MinerData: async def get_data(self) -> MinerData:
"""Get data from the miner.
Returns:
A [`MinerData`][pyasic.data.MinerData] instance containing the miners data.
"""
data = MinerData(ip=str(self.ip), ideal_chips=self.nominal_chips * 3) data = MinerData(ip=str(self.ip), ideal_chips=self.nominal_chips * 3)
board_offset = -1 board_offset = -1

View File

@@ -197,6 +197,11 @@ MINER_CLASSES = {
"Default": BTMinerM31SPlus, "Default": BTMinerM31SPlus,
"BTMiner": BTMinerM31SPlus, "BTMiner": BTMinerM31SPlus,
"E20": BTMinerM31SPlusVE20, "E20": BTMinerM31SPlusVE20,
"30": BTMinerM31SPlusV30,
"40": BTMinerM31SPlusV40,
"60": BTMinerM31SPlusV60,
"80": BTMinerM31SPlusV80,
"90": BTMinerM31SPlusV90,
}, },
"M32S": { "M32S": {
"Default": BTMinerM32S, "Default": BTMinerM32S,

View File

@@ -12,10 +12,13 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
from typing import List
from pyasic.API.unknown import UnknownAPI from pyasic.API.unknown import UnknownAPI
from pyasic.miners.base import BaseMiner from pyasic.miners.base import BaseMiner
from pyasic.config import MinerConfig from pyasic.config import MinerConfig
from pyasic.data import MinerData from pyasic.data import MinerData
from pyasic.data.error_codes import MinerErrorData
class UnknownMiner(BaseMiner): class UnknownMiner(BaseMiner):
@@ -48,7 +51,7 @@ class UnknownMiner(BaseMiner):
async def get_config(self) -> None: async def get_config(self) -> None:
return None return None
async def get_errors(self) -> list: async def get_errors(self) -> List[MinerErrorData]:
return [] return []
async def get_mac(self) -> str: async def get_mac(self) -> str:
@@ -60,6 +63,12 @@ class UnknownMiner(BaseMiner):
async def restart_backend(self) -> bool: async def restart_backend(self) -> bool:
return False return False
async def stop_mining(self) -> bool:
return False
async def resume_mining(self) -> bool:
return False
async def send_config(self, config: MinerConfig, user_suffix: str = None) -> None: async def send_config(self, config: MinerConfig, user_suffix: str = None) -> None:
return None return None

View File

@@ -16,6 +16,11 @@ from pyasic.miners._backends import BTMiner # noqa - Ignore access to _module
from pyasic.miners._types import ( from pyasic.miners._types import (
M31SPlus, M31SPlus,
M31SPlusVE20, M31SPlusVE20,
M31SPlusV30,
M31SPlusV40,
M31SPlusV60,
M31SPlusV80,
M31SPlusV90,
) # noqa - Ignore access to _module ) # noqa - Ignore access to _module
@@ -29,3 +34,33 @@ class BTMinerM31SPlusVE20(BTMiner, M31SPlusVE20):
def __init__(self, ip: str) -> None: def __init__(self, ip: str) -> None:
super().__init__(ip) super().__init__(ip)
self.ip = ip self.ip = ip
class BTMinerM31SPlusV30(BTMiner, M31SPlusV30):
def __init__(self, ip: str) -> None:
super().__init__(ip)
self.ip = ip
class BTMinerM31SPlusV40(BTMiner, M31SPlusV40):
def __init__(self, ip: str) -> None:
super().__init__(ip)
self.ip = ip
class BTMinerM31SPlusV60(BTMiner, M31SPlusV60):
def __init__(self, ip: str) -> None:
super().__init__(ip)
self.ip = ip
class BTMinerM31SPlusV80(BTMiner, M31SPlusV80):
def __init__(self, ip: str) -> None:
super().__init__(ip)
self.ip = ip
class BTMinerM31SPlusV90(BTMiner, M31SPlusV90):
def __init__(self, ip: str) -> None:
super().__init__(ip)
self.ip = ip

View File

@@ -33,7 +33,15 @@ from .M30S_Plus_Plus import (
) )
from .M31S import BTMinerM31S from .M31S import BTMinerM31S
from .M31S_Plus import BTMinerM31SPlus, BTMinerM31SPlusVE20 from .M31S_Plus import (
BTMinerM31SPlus,
BTMinerM31SPlusVE20,
BTMinerM31SPlusV30,
BTMinerM31SPlusV40,
BTMinerM31SPlusV60,
BTMinerM31SPlusV80,
BTMinerM31SPlusV90,
)
from .M32 import BTMinerM32, BTMinerM32V20 from .M32 import BTMinerM32, BTMinerM32V20
from .M32S import BTMinerM32S from .M32S import BTMinerM32S

View File

@@ -48,6 +48,7 @@ class MinerNetwork:
if mask.startswith("/"): if mask.startswith("/"):
mask = mask.replace("/", "") mask = mask.replace("/", "")
self.mask = mask self.mask = mask
self.network = self.get_network()
def __len__(self): def __len__(self):
return len([item for item in self.get_network().hosts()]) return len([item for item in self.get_network().hosts()])
@@ -55,6 +56,10 @@ class MinerNetwork:
def __repr__(self): def __repr__(self):
return str(self.network) return str(self.network)
def hosts(self):
for x in self.network.hosts():
yield x
def get_network(self) -> ipaddress.ip_network: def get_network(self) -> ipaddress.ip_network:
"""Get the network using the information passed to the MinerNetwork or from cache. """Get the network using the information passed to the MinerNetwork or from cache.

View File

@@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "pyasic" name = "pyasic"
version = "0.17.4" version = "0.17.9"
description = "A set of modules for interfacing with many common types of ASIC bitcoin miners, using both their API and SSH." description = "A set of modules for interfacing with many common types of ASIC bitcoin miners, using both their API and SSH."
authors = ["UpstreamData <brett@upstreamdata.ca>"] authors = ["UpstreamData <brett@upstreamdata.ca>"]
repository = "https://github.com/UpstreamData/pyasic" repository = "https://github.com/UpstreamData/pyasic"