Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
96bb56ebd1 | ||
|
|
cdd7beccbe | ||
|
|
1a544851df | ||
|
|
84ac991685 | ||
|
|
9da7b44177 | ||
|
|
e7f05f7a28 | ||
|
|
2d229be9fd | ||
|
|
de5038e57a | ||
|
|
8ad1b3f72a | ||
|
|
070fb26dbc | ||
|
|
80d9d7df1d | ||
|
|
928c24f56f | ||
|
|
6e7442f90d | ||
|
|
936474ed3b | ||
|
|
2e28060e05 | ||
|
|
07f92557c6 | ||
|
|
6f6f5743cf | ||
|
|
b89ea1fa92 | ||
|
|
3588197741 | ||
|
|
8adc3d2adf | ||
|
|
040c0b6842 | ||
|
|
550b4a97a1 |
@@ -1,3 +1,3 @@
|
|||||||
jinja2<3.1.0
|
jinja2<3.1.3
|
||||||
mkdocs
|
mkdocs
|
||||||
mkdocstrings[python]
|
mkdocstrings[python]
|
||||||
|
|||||||
@@ -263,6 +263,12 @@ If you are sure you want to use this command please use API.send_command("{comma
|
|||||||
else:
|
else:
|
||||||
return False, data["STATUS"][0]["Msg"]
|
return False, data["STATUS"][0]["Msg"]
|
||||||
|
|
||||||
|
elif isinstance(data["STATUS"], dict):
|
||||||
|
# new style X19 command
|
||||||
|
if data["STATUS"]["STATUS"] not in ["S", "I"]:
|
||||||
|
return False, data["STATUS"]["Msg"]
|
||||||
|
return True, None
|
||||||
|
|
||||||
if data["STATUS"] not in ["S", "I"]:
|
if data["STATUS"] not in ["S", "I"]:
|
||||||
return False, data["Msg"]
|
return False, data["Msg"]
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -48,10 +48,10 @@ PrePowerOnMessage = Union[
|
|||||||
|
|
||||||
|
|
||||||
def _crypt(word: str, salt: str) -> str:
|
def _crypt(word: str, salt: str) -> str:
|
||||||
"""Encrypts a word with a salt, using a standard salt format.
|
r"""Encrypts a word with a salt, using a standard salt format.
|
||||||
|
|
||||||
Encrypts a word using a salt with the format
|
Encrypts a word using a salt with the format
|
||||||
'\s*\$(\d+)\$([\w\./]*)\$'. If this format is not used, a
|
\s*\$(\d+)\$([\w\./]*)\$. If this format is not used, a
|
||||||
ValueError is raised.
|
ValueError is raised.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
@@ -62,7 +62,7 @@ def _crypt(word: str, salt: str) -> str:
|
|||||||
An MD5 hash of the word with the salt.
|
An MD5 hash of the word with the salt.
|
||||||
"""
|
"""
|
||||||
# compile a standard format for the salt
|
# compile a standard format for the salt
|
||||||
standard_salt = re.compile("\s*\$(\d+)\$([\w\./]*)\$")
|
standard_salt = re.compile(r"\s*\$(\d+)\$([\w\./]*)\$")
|
||||||
# check if the salt matches
|
# check if the salt matches
|
||||||
match = standard_salt.match(salt)
|
match = standard_salt.match(salt)
|
||||||
# if the matching fails, the salt is incorrect
|
# if the matching fails, the salt is incorrect
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ from pyasic.data import (
|
|||||||
)
|
)
|
||||||
from pyasic.errors import APIError, APIWarning
|
from pyasic.errors import APIError, APIWarning
|
||||||
from pyasic.miners import get_miner
|
from pyasic.miners import get_miner
|
||||||
from pyasic.miners.base import AnyMiner
|
from pyasic.miners.base import AnyMiner, DataOptions
|
||||||
from pyasic.miners.miner_factory import MinerFactory, miner_factory
|
from pyasic.miners.miner_factory import MinerFactory, miner_factory
|
||||||
from pyasic.miners.miner_listener import MinerListener
|
from pyasic.miners.miner_listener import MinerListener
|
||||||
from pyasic.network import MinerNetwork
|
from pyasic.network import MinerNetwork
|
||||||
@@ -50,6 +50,7 @@ __all__ = [
|
|||||||
"APIWarning",
|
"APIWarning",
|
||||||
"get_miner",
|
"get_miner",
|
||||||
"AnyMiner",
|
"AnyMiner",
|
||||||
|
"DataOptions",
|
||||||
"MinerFactory",
|
"MinerFactory",
|
||||||
"miner_factory",
|
"miner_factory",
|
||||||
"MinerListener",
|
"MinerListener",
|
||||||
|
|||||||
@@ -161,6 +161,24 @@ class MinerConfig:
|
|||||||
power_scaling=PowerScalingConfig.from_bosminer(toml_conf),
|
power_scaling=PowerScalingConfig.from_bosminer(toml_conf),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_epic(cls, web_conf: dict) -> "MinerConfig":
|
||||||
|
return cls(
|
||||||
|
pools=PoolConfig.from_epic(web_conf),
|
||||||
|
fan_mode=FanModeConfig.from_epic(web_conf),
|
||||||
|
temperature=TemperatureConfig.from_epic(web_conf),
|
||||||
|
mining_mode=MiningModeConfig.from_epic(web_conf),
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_vnish(cls, web_settings: dict) -> "MinerConfig":
|
||||||
|
return cls(
|
||||||
|
pools=PoolConfig.from_vnish(web_settings),
|
||||||
|
fan_mode=FanModeConfig.from_vnish(web_settings),
|
||||||
|
temperature=TemperatureConfig.from_vnish(web_settings),
|
||||||
|
mining_mode=MiningModeConfig.from_vnish(web_settings),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def merge(a: dict, b: dict) -> dict:
|
def merge(a: dict, b: dict) -> dict:
|
||||||
result = deepcopy(a)
|
result = deepcopy(a)
|
||||||
|
|||||||
@@ -50,6 +50,9 @@ class MinerConfigOption(Enum):
|
|||||||
def as_epic(self) -> dict:
|
def as_epic(self) -> dict:
|
||||||
return self.value.as_epic()
|
return self.value.as_epic()
|
||||||
|
|
||||||
|
def as_vnish(self) -> dict:
|
||||||
|
return self.value.as_vnish()
|
||||||
|
|
||||||
def __call__(self, *args, **kwargs):
|
def __call__(self, *args, **kwargs):
|
||||||
return self.value(*args, **kwargs)
|
return self.value(*args, **kwargs)
|
||||||
|
|
||||||
@@ -93,3 +96,6 @@ class MinerConfigValue:
|
|||||||
|
|
||||||
def as_epic(self) -> dict:
|
def as_epic(self) -> dict:
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
def as_vnish(self) -> dict:
|
||||||
|
return {}
|
||||||
|
|||||||
@@ -22,10 +22,26 @@ from pyasic.config.base import MinerConfigOption, MinerConfigValue
|
|||||||
@dataclass
|
@dataclass
|
||||||
class FanModeNormal(MinerConfigValue):
|
class FanModeNormal(MinerConfigValue):
|
||||||
mode: str = field(init=False, default="normal")
|
mode: str = field(init=False, default="normal")
|
||||||
|
minimum_fans: int = 1
|
||||||
|
minimum_speed: int = 0
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_dict(cls, dict_conf: Union[dict, None]) -> "FanModeNormal":
|
def from_dict(cls, dict_conf: Union[dict, None]) -> "FanModeNormal":
|
||||||
return cls()
|
cls_conf = {}
|
||||||
|
if dict_conf.get("minimum_fans") is not None:
|
||||||
|
cls_conf["minimum_fans"] = dict_conf["minimum_fans"]
|
||||||
|
if dict_conf.get("minimum_speed") is not None:
|
||||||
|
cls_conf["minimum_speed"] = dict_conf["minimum_speed"]
|
||||||
|
return cls(**cls_conf)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_vnish(cls, web_cooling_settings: dict):
|
||||||
|
cls_conf = {}
|
||||||
|
if web_cooling_settings.get("fan_min_count") is not None:
|
||||||
|
cls_conf["minimum_fans"] = web_cooling_settings["fan_min_count"]
|
||||||
|
if web_cooling_settings.get("fan_min_duty") is not None:
|
||||||
|
cls_conf["minimum_speed"] = web_cooling_settings["fan_min_duty"]
|
||||||
|
return cls(**cls_conf)
|
||||||
|
|
||||||
def as_am_modern(self) -> dict:
|
def as_am_modern(self) -> dict:
|
||||||
return {"bitmain-fan-ctrl": False, "bitmain-fan-pwn": "100"}
|
return {"bitmain-fan-ctrl": False, "bitmain-fan-pwn": "100"}
|
||||||
@@ -58,6 +74,15 @@ class FanModeManual(MinerConfigValue):
|
|||||||
cls_conf["speed"] = toml_fan_conf["speed"]
|
cls_conf["speed"] = toml_fan_conf["speed"]
|
||||||
return cls(**cls_conf)
|
return cls(**cls_conf)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_vnish(cls, web_cooling_settings: dict) -> "FanModeManual":
|
||||||
|
cls_conf = {}
|
||||||
|
if web_cooling_settings.get("fan_min_count") is not None:
|
||||||
|
cls_conf["minimum_fans"] = web_cooling_settings["fan_min_count"]
|
||||||
|
if web_cooling_settings["mode"].get("param") is not None:
|
||||||
|
cls_conf["speed"] = web_cooling_settings["mode"]["param"]
|
||||||
|
return cls(**cls_conf)
|
||||||
|
|
||||||
def as_am_modern(self) -> dict:
|
def as_am_modern(self) -> dict:
|
||||||
return {"bitmain-fan-ctrl": True, "bitmain-fan-pwn": str(self.speed)}
|
return {"bitmain-fan-ctrl": True, "bitmain-fan-pwn": str(self.speed)}
|
||||||
|
|
||||||
@@ -116,6 +141,17 @@ class FanModeConfig(MinerConfigOption):
|
|||||||
else:
|
else:
|
||||||
return cls.default()
|
return cls.default()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_epic(cls, web_conf: dict):
|
||||||
|
try:
|
||||||
|
fan_mode = web_conf["Fans"]["Fan Mode"]
|
||||||
|
if fan_mode.get("Manual") is not None:
|
||||||
|
return cls.manual(speed=fan_mode.get("Manual"))
|
||||||
|
else:
|
||||||
|
return cls.normal()
|
||||||
|
except KeyError:
|
||||||
|
return cls.default()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_bosminer(cls, toml_conf: dict):
|
def from_bosminer(cls, toml_conf: dict):
|
||||||
if toml_conf.get("temp_control") is None:
|
if toml_conf.get("temp_control") is None:
|
||||||
@@ -132,3 +168,17 @@ class FanModeConfig(MinerConfigOption):
|
|||||||
return cls.manual()
|
return cls.manual()
|
||||||
elif mode == "disabled":
|
elif mode == "disabled":
|
||||||
return cls.immersion()
|
return cls.immersion()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_vnish(cls, web_settings: dict):
|
||||||
|
try:
|
||||||
|
mode = web_settings["miner"]["cooling"]["mode"]["name"]
|
||||||
|
except LookupError:
|
||||||
|
return cls.default()
|
||||||
|
|
||||||
|
if mode == "auto":
|
||||||
|
return cls.normal().from_vnish(web_settings["miner"]["cooling"])
|
||||||
|
elif mode == "manual":
|
||||||
|
return cls.manual().from_vnish(web_settings["miner"]["cooling"])
|
||||||
|
elif mode == "immers":
|
||||||
|
return cls.immersion()
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
# limitations under the License. -
|
# limitations under the License. -
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from typing import Union
|
from typing import Dict, Union
|
||||||
|
|
||||||
from pyasic.config.base import MinerConfigOption, MinerConfigValue
|
from pyasic.config.base import MinerConfigOption, MinerConfigValue
|
||||||
|
|
||||||
@@ -132,7 +132,7 @@ class MiningModeManual(MinerConfigValue):
|
|||||||
|
|
||||||
global_freq: float
|
global_freq: float
|
||||||
global_volt: float
|
global_volt: float
|
||||||
boards: dict[int, ManualBoardSettings] = field(default_factory=dict)
|
boards: Dict[int, ManualBoardSettings] = field(default_factory=dict)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_dict(cls, dict_conf: Union[dict, None]) -> "MiningModeManual":
|
def from_dict(cls, dict_conf: Union[dict, None]) -> "MiningModeManual":
|
||||||
@@ -145,6 +145,20 @@ class MiningModeManual(MinerConfigValue):
|
|||||||
def as_am_modern(self) -> dict:
|
def as_am_modern(self) -> dict:
|
||||||
return {"miner-mode": "0"}
|
return {"miner-mode": "0"}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_vnish(cls, web_overclock_settings: dict) -> "MiningModeManual":
|
||||||
|
# will raise KeyError if it cant find the settings, values cannot be empty
|
||||||
|
voltage = web_overclock_settings["globals"]["volt"]
|
||||||
|
freq = web_overclock_settings["globals"]["freq"]
|
||||||
|
boards = {
|
||||||
|
idx: ManualBoardSettings(
|
||||||
|
freq=board["freq"],
|
||||||
|
volt=voltage if not board["freq"] == 0 else 0,
|
||||||
|
)
|
||||||
|
for idx, board in enumerate(web_overclock_settings["chains"])
|
||||||
|
}
|
||||||
|
return cls(global_freq=freq, global_volt=voltage, boards=boards)
|
||||||
|
|
||||||
|
|
||||||
class MiningModeConfig(MinerConfigOption):
|
class MiningModeConfig(MinerConfigOption):
|
||||||
normal = MiningModeNormal
|
normal = MiningModeNormal
|
||||||
@@ -186,6 +200,29 @@ class MiningModeConfig(MinerConfigOption):
|
|||||||
return cls.low()
|
return cls.low()
|
||||||
return cls.default()
|
return cls.default()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_epic(cls, web_conf: dict):
|
||||||
|
try:
|
||||||
|
work_mode = web_conf["PerpetualTune"]["Running"]
|
||||||
|
if work_mode:
|
||||||
|
if (
|
||||||
|
web_conf["PerpetualTune"]["Algorithm"].get("VoltageOptimizer")
|
||||||
|
is not None
|
||||||
|
):
|
||||||
|
return cls.hashrate_tuning(
|
||||||
|
web_conf["PerpetualTune"]["Algorithm"]["VoltageOptimizer"][
|
||||||
|
"Target"
|
||||||
|
]
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return cls.hashrate_tuning(
|
||||||
|
web_conf["PerpetualTune"]["Algorithm"]["ChipTune"]["Target"]
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return cls.normal()
|
||||||
|
except KeyError:
|
||||||
|
return cls.default()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_bosminer(cls, toml_conf: dict):
|
def from_bosminer(cls, toml_conf: dict):
|
||||||
if toml_conf.get("autotuning") is None:
|
if toml_conf.get("autotuning") is None:
|
||||||
@@ -211,3 +248,15 @@ class MiningModeConfig(MinerConfigOption):
|
|||||||
if autotuning_conf.get("hashrate_target") is not None:
|
if autotuning_conf.get("hashrate_target") is not None:
|
||||||
return cls.hashrate_tuning(autotuning_conf["hashrate_target"])
|
return cls.hashrate_tuning(autotuning_conf["hashrate_target"])
|
||||||
return cls.hashrate_tuning()
|
return cls.hashrate_tuning()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_vnish(cls, web_settings: dict):
|
||||||
|
try:
|
||||||
|
mode_settings = web_settings["miner"]["overclock"]
|
||||||
|
except KeyError:
|
||||||
|
return cls.default()
|
||||||
|
|
||||||
|
if mode_settings["preset"] == "disabled":
|
||||||
|
return MiningModeManual.from_vnish(mode_settings)
|
||||||
|
else:
|
||||||
|
return cls.power_tuning(int(mode_settings["preset"]))
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
import random
|
import random
|
||||||
import string
|
import string
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from typing import Union
|
from typing import Dict, List, Union
|
||||||
|
|
||||||
from pyasic.config.base import MinerConfigValue
|
from pyasic.config.base import MinerConfigValue
|
||||||
|
|
||||||
@@ -108,6 +108,12 @@ class Pool(MinerConfigValue):
|
|||||||
def from_api(cls, api_pool: dict) -> "Pool":
|
def from_api(cls, api_pool: dict) -> "Pool":
|
||||||
return cls(url=api_pool["URL"], user=api_pool["User"], password="x")
|
return cls(url=api_pool["URL"], user=api_pool["User"], password="x")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_epic(cls, api_pool: dict) -> "Pool":
|
||||||
|
return cls(
|
||||||
|
url=api_pool["pool"], user=api_pool["login"], password=api_pool["password"]
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_am_modern(cls, web_pool: dict) -> "Pool":
|
def from_am_modern(cls, web_pool: dict) -> "Pool":
|
||||||
return cls(
|
return cls(
|
||||||
@@ -135,10 +141,18 @@ class Pool(MinerConfigValue):
|
|||||||
password=toml_pool_conf["password"],
|
password=toml_pool_conf["password"],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_vnish(cls, web_pool: dict) -> "Pool":
|
||||||
|
return cls(
|
||||||
|
url=web_pool["url"],
|
||||||
|
user=web_pool["user"],
|
||||||
|
password=web_pool["pass"],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class PoolGroup(MinerConfigValue):
|
class PoolGroup(MinerConfigValue):
|
||||||
pools: list[Pool] = field(default_factory=list)
|
pools: List[Pool] = field(default_factory=list)
|
||||||
quota: int = 1
|
quota: int = 1
|
||||||
name: str = None
|
name: str = None
|
||||||
|
|
||||||
@@ -237,6 +251,13 @@ class PoolGroup(MinerConfigValue):
|
|||||||
pools.append(Pool.from_api(pool))
|
pools.append(Pool.from_api(pool))
|
||||||
return cls(pools=pools)
|
return cls(pools=pools)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_epic(cls, api_pool_list: list) -> "PoolGroup":
|
||||||
|
pools = []
|
||||||
|
for pool in api_pool_list:
|
||||||
|
pools.append(Pool.from_epic(pool))
|
||||||
|
return cls(pools=pools)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_am_modern(cls, web_pool_list: list) -> "PoolGroup":
|
def from_am_modern(cls, web_pool_list: list) -> "PoolGroup":
|
||||||
pools = []
|
pools = []
|
||||||
@@ -262,10 +283,14 @@ class PoolGroup(MinerConfigValue):
|
|||||||
)
|
)
|
||||||
return cls()
|
return cls()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_vnish(cls, web_settings_pools: dict) -> "PoolGroup":
|
||||||
|
return cls([Pool.from_vnish(p) for p in web_settings_pools])
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class PoolConfig(MinerConfigValue):
|
class PoolConfig(MinerConfigValue):
|
||||||
groups: list[PoolGroup] = field(default_factory=list)
|
groups: List[PoolGroup] = field(default_factory=list)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def default(cls) -> "PoolConfig":
|
def default(cls) -> "PoolConfig":
|
||||||
@@ -279,7 +304,7 @@ class PoolConfig(MinerConfigValue):
|
|||||||
return cls(groups=[PoolGroup.from_dict(g) for g in dict_conf["groups"]])
|
return cls(groups=[PoolGroup.from_dict(g) for g in dict_conf["groups"]])
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def simple(cls, pools: list[Union[Pool, dict[str, str]]]) -> "PoolConfig":
|
def simple(cls, pools: List[Union[Pool, Dict[str, str]]]) -> "PoolConfig":
|
||||||
group_pools = []
|
group_pools = []
|
||||||
for pool in pools:
|
for pool in pools:
|
||||||
if isinstance(pool, dict):
|
if isinstance(pool, dict):
|
||||||
@@ -329,11 +354,19 @@ class PoolConfig(MinerConfigValue):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_api(cls, api_pools: dict) -> "PoolConfig":
|
def from_api(cls, api_pools: dict) -> "PoolConfig":
|
||||||
|
try:
|
||||||
pool_data = api_pools["POOLS"]
|
pool_data = api_pools["POOLS"]
|
||||||
|
except KeyError:
|
||||||
|
return PoolConfig.default()
|
||||||
pool_data = sorted(pool_data, key=lambda x: int(x["POOL"]))
|
pool_data = sorted(pool_data, key=lambda x: int(x["POOL"]))
|
||||||
|
|
||||||
return cls([PoolGroup.from_api(pool_data)])
|
return cls([PoolGroup.from_api(pool_data)])
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_epic(cls, web_conf: dict) -> "PoolConfig":
|
||||||
|
pool_data = web_conf["StratumConfigs"]
|
||||||
|
return cls([PoolGroup.from_epic(pool_data)])
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_am_modern(cls, web_conf: dict) -> "PoolConfig":
|
def from_am_modern(cls, web_conf: dict) -> "PoolConfig":
|
||||||
pool_data = web_conf["pools"]
|
pool_data = web_conf["pools"]
|
||||||
@@ -354,3 +387,10 @@ class PoolConfig(MinerConfigValue):
|
|||||||
return cls()
|
return cls()
|
||||||
|
|
||||||
return cls([PoolGroup.from_bosminer(g) for g in toml_conf["group"]])
|
return cls([PoolGroup.from_bosminer(g) for g in toml_conf["group"]])
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_vnish(cls, web_settings: dict) -> "PoolConfig":
|
||||||
|
try:
|
||||||
|
return cls([PoolGroup.from_vnish(web_settings["miner"]["pools"])])
|
||||||
|
except LookupError:
|
||||||
|
return cls()
|
||||||
|
|||||||
@@ -56,3 +56,27 @@ class TemperatureConfig(MinerConfigValue):
|
|||||||
hot=temp_control.get("hot_temp"),
|
hot=temp_control.get("hot_temp"),
|
||||||
danger=temp_control.get("dangerous_temp"),
|
danger=temp_control.get("dangerous_temp"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_epic(cls, web_conf: dict) -> "TemperatureConfig":
|
||||||
|
dangerous_temp = None
|
||||||
|
try:
|
||||||
|
hot_temp = web_conf["Misc"]["Shutdown Temp"]
|
||||||
|
except KeyError:
|
||||||
|
hot_temp = None
|
||||||
|
# Need to do this in two blocks to avoid KeyError if one is missing
|
||||||
|
try:
|
||||||
|
target_temp = web_conf["Fans"]["Fan Mode"]["Auto"]["Target Temperature"]
|
||||||
|
except KeyError:
|
||||||
|
target_temp = None
|
||||||
|
|
||||||
|
return cls(target=target_temp, hot=hot_temp, danger=dangerous_temp)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_vnish(cls, web_settings: dict):
|
||||||
|
try:
|
||||||
|
if web_settings["miner"]["cooling"]["mode"]["name"] == "auto":
|
||||||
|
return cls(target=web_settings["miner"]["cooling"]["mode"]["param"])
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
return cls()
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ class HashBoard:
|
|||||||
chip_temp: int = None
|
chip_temp: int = None
|
||||||
chips: int = None
|
chips: int = None
|
||||||
expected_chips: int = None
|
expected_chips: int = None
|
||||||
|
serial_number: str = None
|
||||||
missing: bool = True
|
missing: bool = True
|
||||||
|
|
||||||
def get(self, __key: str, default: Any = None):
|
def get(self, __key: str, default: Any = None):
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ from pyasic.miners.types import (
|
|||||||
S19jPro,
|
S19jPro,
|
||||||
S19Plus,
|
S19Plus,
|
||||||
S19Pro,
|
S19Pro,
|
||||||
|
S19ProHydro,
|
||||||
S19ProPlus,
|
S19ProPlus,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -77,3 +78,7 @@ class BMMinerS19jPro(AntminerModern, S19jPro):
|
|||||||
|
|
||||||
class BMMinerS19L(AntminerModern, S19L):
|
class BMMinerS19L(AntminerModern, S19L):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class BMMinerS19ProHydro(AntminerModern, S19ProHydro):
|
||||||
|
pass
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ from .S19 import (
|
|||||||
BMMinerS19L,
|
BMMinerS19L,
|
||||||
BMMinerS19Plus,
|
BMMinerS19Plus,
|
||||||
BMMinerS19Pro,
|
BMMinerS19Pro,
|
||||||
|
BMMinerS19ProHydro,
|
||||||
BMMinerS19ProPlus,
|
BMMinerS19ProPlus,
|
||||||
BMMinerS19XP,
|
BMMinerS19XP,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -14,7 +14,6 @@
|
|||||||
# limitations under the License. -
|
# limitations under the License. -
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
import asyncio
|
|
||||||
from typing import List, Optional, Union
|
from typing import List, Optional, Union
|
||||||
|
|
||||||
from pyasic.API import APIError
|
from pyasic.API import APIError
|
||||||
@@ -23,50 +22,60 @@ from pyasic.data import Fan, HashBoard
|
|||||||
from pyasic.data.error_codes import MinerErrorData, X19Error
|
from pyasic.data.error_codes import MinerErrorData, X19Error
|
||||||
from pyasic.miners.backends.bmminer import BMMiner
|
from pyasic.miners.backends.bmminer import BMMiner
|
||||||
from pyasic.miners.backends.cgminer import CGMiner
|
from pyasic.miners.backends.cgminer import CGMiner
|
||||||
|
from pyasic.miners.base import (
|
||||||
|
DataFunction,
|
||||||
|
DataLocations,
|
||||||
|
DataOptions,
|
||||||
|
RPCAPICommand,
|
||||||
|
WebAPICommand,
|
||||||
|
)
|
||||||
from pyasic.web.antminer import AntminerModernWebAPI, AntminerOldWebAPI
|
from pyasic.web.antminer import AntminerModernWebAPI, AntminerOldWebAPI
|
||||||
|
|
||||||
ANTMINER_MODERN_DATA_LOC = {
|
ANTMINER_MODERN_DATA_LOC = DataLocations(
|
||||||
"mac": {
|
**{
|
||||||
"cmd": "get_mac",
|
str(DataOptions.MAC): DataFunction(
|
||||||
"kwargs": {"web_get_system_info": {"web": "get_system_info"}},
|
"get_mac", [WebAPICommand("web_get_system_info", "get_system_info")]
|
||||||
},
|
),
|
||||||
"model": {"cmd": "get_model", "kwargs": {}},
|
str(DataOptions.MODEL): DataFunction("get_model"),
|
||||||
"api_ver": {"cmd": "get_api_ver", "kwargs": {"api_version": {"api": "version"}}},
|
str(DataOptions.API_VERSION): DataFunction(
|
||||||
"fw_ver": {"cmd": "get_fw_ver", "kwargs": {"api_version": {"api": "version"}}},
|
"get_api_ver", [RPCAPICommand("api_version", "version")]
|
||||||
"hostname": {
|
),
|
||||||
"cmd": "get_hostname",
|
str(DataOptions.FW_VERSION): DataFunction(
|
||||||
"kwargs": {"web_get_system_info": {"web": "get_system_info"}},
|
"get_fw_ver", [RPCAPICommand("api_version", "version")]
|
||||||
},
|
),
|
||||||
"hashrate": {"cmd": "get_hashrate", "kwargs": {"api_summary": {"api": "summary"}}},
|
str(DataOptions.HOSTNAME): DataFunction(
|
||||||
"expected_hashrate": {
|
"get_hostname", [WebAPICommand("web_get_system_info", "get_system_info")]
|
||||||
"cmd": "get_expected_hashrate",
|
),
|
||||||
"kwargs": {"api_stats": {"api": "stats"}},
|
str(DataOptions.HASHRATE): DataFunction(
|
||||||
},
|
"get_hashrate", [RPCAPICommand("api_summary", "summary")]
|
||||||
"hashboards": {"cmd": "get_hashboards", "kwargs": {"api_stats": {"api": "stats"}}},
|
),
|
||||||
"env_temp": {"cmd": "get_env_temp", "kwargs": {}},
|
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
|
||||||
"wattage": {"cmd": "get_wattage", "kwargs": {}},
|
"get_expected_hashrate", [RPCAPICommand("api_stats", "stats")]
|
||||||
"wattage_limit": {"cmd": "get_wattage_limit", "kwargs": {}},
|
),
|
||||||
"fans": {"cmd": "get_fans", "kwargs": {"api_stats": {"api": "stats"}}},
|
str(DataOptions.HASHBOARDS): DataFunction("get_hashboards", []),
|
||||||
"fan_psu": {"cmd": "get_fan_psu", "kwargs": {}},
|
str(DataOptions.ENVIRONMENT_TEMP): DataFunction("get_env_temp"),
|
||||||
"errors": {"cmd": "get_errors", "kwargs": {"web_summary": {"web": "summary"}}},
|
str(DataOptions.WATTAGE): DataFunction("get_wattage"),
|
||||||
"fault_light": {
|
str(DataOptions.WATTAGE_LIMIT): DataFunction("get_wattage_limit"),
|
||||||
"cmd": "get_fault_light",
|
str(DataOptions.FANS): DataFunction(
|
||||||
"kwargs": {"web_get_blink_status": {"web": "get_blink_status"}},
|
"get_fans", [RPCAPICommand("api_stats", "stats")]
|
||||||
},
|
),
|
||||||
"pools": {"cmd": "get_pools", "kwargs": {"api_pools": {"api": "pools"}}},
|
str(DataOptions.FAN_PSU): DataFunction("get_fan_psu"),
|
||||||
"is_mining": {
|
str(DataOptions.ERRORS): DataFunction(
|
||||||
"cmd": "is_mining",
|
"get_errors", [WebAPICommand("web_summary", "summary")]
|
||||||
"kwargs": {"web_get_conf": {"web": "get_miner_conf"}},
|
),
|
||||||
},
|
str(DataOptions.FAULT_LIGHT): DataFunction(
|
||||||
"uptime": {
|
"get_fault_light",
|
||||||
"cmd": "get_uptime",
|
[WebAPICommand("web_get_blink_status", "get_blink_status")],
|
||||||
"kwargs": {"api_stats": {"api": "stats"}},
|
),
|
||||||
},
|
str(DataOptions.IS_MINING): DataFunction(
|
||||||
"config": {
|
"is_mining", [WebAPICommand("web_get_conf", "get_miner_conf")]
|
||||||
"cmd": "get_config",
|
),
|
||||||
"kwargs": {},
|
str(DataOptions.UPTIME): DataFunction(
|
||||||
},
|
"get_uptime", [RPCAPICommand("api_stats", "stats")]
|
||||||
|
),
|
||||||
|
str(DataOptions.CONFIG): DataFunction("get_config"),
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class AntminerModern(BMMiner):
|
class AntminerModern(BMMiner):
|
||||||
@@ -185,6 +194,42 @@ class AntminerModern(BMMiner):
|
|||||||
pass
|
pass
|
||||||
return errors
|
return errors
|
||||||
|
|
||||||
|
async def get_hashboards(self) -> List[HashBoard]:
|
||||||
|
hashboards = [
|
||||||
|
HashBoard(idx, expected_chips=self.expected_chips)
|
||||||
|
for idx in range(self.expected_hashboards)
|
||||||
|
]
|
||||||
|
|
||||||
|
try:
|
||||||
|
api_stats = await self.api.send_command("stats", new_api=True)
|
||||||
|
except APIError:
|
||||||
|
return hashboards
|
||||||
|
|
||||||
|
if api_stats:
|
||||||
|
try:
|
||||||
|
for board in api_stats["STATS"][0]["chain"]:
|
||||||
|
hashboards[board["index"]].hashrate = round(
|
||||||
|
board["rate_real"] / 1000, 2
|
||||||
|
)
|
||||||
|
hashboards[board["index"]].chips = board["asic_num"]
|
||||||
|
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
|
||||||
|
)
|
||||||
|
chip_temp_data = list(
|
||||||
|
filter(lambda x: not x == 0, board["temp_chip"])
|
||||||
|
)
|
||||||
|
hashboards[board["index"]].chip_temp = sum(chip_temp_data) / len(
|
||||||
|
chip_temp_data
|
||||||
|
)
|
||||||
|
hashboards[board["index"]].serial_number = board["sn"]
|
||||||
|
hashboards[board["index"]].missing = False
|
||||||
|
except LookupError:
|
||||||
|
pass
|
||||||
|
return hashboards
|
||||||
|
|
||||||
async def get_fault_light(self, web_get_blink_status: dict = None) -> bool:
|
async def get_fault_light(self, web_get_blink_status: dict = None) -> bool:
|
||||||
if self.light:
|
if self.light:
|
||||||
return self.light
|
return self.light
|
||||||
@@ -298,39 +343,49 @@ class AntminerModern(BMMiner):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
ANTMINER_OLD_DATA_LOC = {
|
ANTMINER_OLD_DATA_LOC = DataLocations(
|
||||||
"mac": {"cmd": "get_mac", "kwargs": {}},
|
**{
|
||||||
"model": {"cmd": "get_model", "kwargs": {}},
|
str(DataOptions.MAC): DataFunction("get_mac"),
|
||||||
"api_ver": {"cmd": "get_api_ver", "kwargs": {"api_version": {"api": "version"}}},
|
str(DataOptions.MODEL): DataFunction("get_model"),
|
||||||
"fw_ver": {"cmd": "get_fw_ver", "kwargs": {"api_version": {"api": "version"}}},
|
str(DataOptions.API_VERSION): DataFunction(
|
||||||
"hostname": {
|
"get_api_ver", [RPCAPICommand("api_version", "version")]
|
||||||
"cmd": "get_hostname",
|
),
|
||||||
"kwargs": {"web_get_system_info": {"web": "get_system_info"}},
|
str(DataOptions.FW_VERSION): DataFunction(
|
||||||
},
|
"get_fw_ver", [RPCAPICommand("api_version", "version")]
|
||||||
"hashrate": {"cmd": "get_hashrate", "kwargs": {"api_summary": {"api": "summary"}}},
|
),
|
||||||
"expected_hashrate": {
|
str(DataOptions.HOSTNAME): DataFunction(
|
||||||
"cmd": "get_expected_hashrate",
|
"get_hostname", [WebAPICommand("web_get_system_info", "get_system_info")]
|
||||||
"kwargs": {"api_stats": {"api": "stats"}},
|
),
|
||||||
},
|
str(DataOptions.HASHRATE): DataFunction(
|
||||||
"hashboards": {"cmd": "get_hashboards", "kwargs": {"api_stats": {"api": "stats"}}},
|
"get_hashrate", [RPCAPICommand("api_summary", "summary")]
|
||||||
"env_temp": {"cmd": "get_env_temp", "kwargs": {}},
|
),
|
||||||
"wattage": {"cmd": "get_wattage", "kwargs": {}},
|
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
|
||||||
"wattage_limit": {"cmd": "get_wattage_limit", "kwargs": {}},
|
"get_expected_hashrate", [RPCAPICommand("api_stats", "stats")]
|
||||||
"fans": {"cmd": "get_fans", "kwargs": {"api_stats": {"api": "stats"}}},
|
),
|
||||||
"fan_psu": {"cmd": "get_fan_psu", "kwargs": {}},
|
str(DataOptions.HASHBOARDS): DataFunction(
|
||||||
"errors": {"cmd": "get_errors", "kwargs": {}},
|
"get_hashboards", [RPCAPICommand("api_stats", "stats")]
|
||||||
"fault_light": {
|
),
|
||||||
"cmd": "get_fault_light",
|
str(DataOptions.ENVIRONMENT_TEMP): DataFunction("get_env_temp"),
|
||||||
"kwargs": {"web_get_blink_status": {"web": "get_blink_status"}},
|
str(DataOptions.WATTAGE): DataFunction("get_wattage"),
|
||||||
},
|
str(DataOptions.WATTAGE_LIMIT): DataFunction("get_wattage_limit"),
|
||||||
"pools": {"cmd": "get_pools", "kwargs": {"api_pools": {"api": "pools"}}},
|
str(DataOptions.FANS): DataFunction(
|
||||||
"is_mining": {
|
"get_fans", [RPCAPICommand("api_stats", "stats")]
|
||||||
"cmd": "is_mining",
|
),
|
||||||
"kwargs": {"web_get_conf": {"web": "get_miner_conf"}},
|
str(DataOptions.FAN_PSU): DataFunction("get_fan_psu"),
|
||||||
},
|
str(DataOptions.ERRORS): DataFunction("get_errors"),
|
||||||
"uptime": {"cmd": "get_uptime", "kwargs": {"api_stats": {"api": "stats"}}},
|
str(DataOptions.FAULT_LIGHT): DataFunction(
|
||||||
"config": {"cmd": "get_config", "kwargs": {}},
|
"get_fault_light",
|
||||||
|
[WebAPICommand("web_get_blink_status", "get_blink_status")],
|
||||||
|
),
|
||||||
|
str(DataOptions.IS_MINING): DataFunction(
|
||||||
|
"is_mining", [WebAPICommand("web_get_conf", "get_miner_conf")]
|
||||||
|
),
|
||||||
|
str(DataOptions.UPTIME): DataFunction(
|
||||||
|
"get_uptime", [RPCAPICommand("api_stats", "stats")]
|
||||||
|
),
|
||||||
|
str(DataOptions.CONFIG): DataFunction("get_config"),
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class AntminerOld(CGMiner):
|
class AntminerOld(CGMiner):
|
||||||
|
|||||||
@@ -22,32 +22,48 @@ from pyasic.config import MinerConfig
|
|||||||
from pyasic.data import Fan, HashBoard
|
from pyasic.data import Fan, HashBoard
|
||||||
from pyasic.data.error_codes import MinerErrorData
|
from pyasic.data.error_codes import MinerErrorData
|
||||||
from pyasic.errors import APIError
|
from pyasic.errors import APIError
|
||||||
from pyasic.miners.base import BaseMiner
|
from pyasic.miners.base import (
|
||||||
|
BaseMiner,
|
||||||
|
DataFunction,
|
||||||
|
DataLocations,
|
||||||
|
DataOptions,
|
||||||
|
RPCAPICommand,
|
||||||
|
)
|
||||||
|
|
||||||
BFGMINER_DATA_LOC = {
|
BFGMINER_DATA_LOC = DataLocations(
|
||||||
"mac": {"cmd": "get_mac", "kwargs": {}},
|
**{
|
||||||
"model": {"cmd": "get_model", "kwargs": {}},
|
str(DataOptions.MAC): DataFunction("get_mac"),
|
||||||
"api_ver": {"cmd": "get_api_ver", "kwargs": {"api_version": {"api": "version"}}},
|
str(DataOptions.MODEL): DataFunction("get_model"),
|
||||||
"fw_ver": {"cmd": "get_fw_ver", "kwargs": {"api_version": {"api": "version"}}},
|
str(DataOptions.API_VERSION): DataFunction(
|
||||||
"hostname": {"cmd": "get_hostname", "kwargs": {}},
|
"get_api_ver", [RPCAPICommand("api_version", "version")]
|
||||||
"hashrate": {"cmd": "get_hashrate", "kwargs": {"api_summary": {"api": "summary"}}},
|
),
|
||||||
"expected_hashrate": {
|
str(DataOptions.FW_VERSION): DataFunction(
|
||||||
"cmd": "get_expected_hashrate",
|
"get_fw_ver", [RPCAPICommand("api_version", "version")]
|
||||||
"kwargs": {"api_stats": {"api": "stats"}},
|
),
|
||||||
},
|
str(DataOptions.HOSTNAME): DataFunction("get_hostname"),
|
||||||
"hashboards": {"cmd": "get_hashboards", "kwargs": {"api_stats": {"api": "stats"}}},
|
str(DataOptions.HASHRATE): DataFunction(
|
||||||
"env_temp": {"cmd": "get_env_temp", "kwargs": {}},
|
"get_hashrate", [RPCAPICommand("api_summary", "summary")]
|
||||||
"wattage": {"cmd": "get_wattage", "kwargs": {}},
|
),
|
||||||
"wattage_limit": {"cmd": "get_wattage_limit", "kwargs": {}},
|
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
|
||||||
"fans": {"cmd": "get_fans", "kwargs": {"api_stats": {"api": "stats"}}},
|
"get_expected_hashrate", [RPCAPICommand("api_stats", "stats")]
|
||||||
"fan_psu": {"cmd": "get_fan_psu", "kwargs": {}},
|
),
|
||||||
"errors": {"cmd": "get_errors", "kwargs": {}},
|
str(DataOptions.HASHBOARDS): DataFunction(
|
||||||
"fault_light": {"cmd": "get_fault_light", "kwargs": {}},
|
"get_hashboards", [RPCAPICommand("api_stats", "stats")]
|
||||||
"pools": {"cmd": "get_pools", "kwargs": {"api_pools": {"api": "pools"}}},
|
),
|
||||||
"is_mining": {"cmd": "is_mining", "kwargs": {}},
|
str(DataOptions.ENVIRONMENT_TEMP): DataFunction("get_env_temp"),
|
||||||
"uptime": {"cmd": "get_uptime", "kwargs": {}},
|
str(DataOptions.WATTAGE): DataFunction("get_wattage"),
|
||||||
"config": {"cmd": "get_config", "kwargs": {}},
|
str(DataOptions.WATTAGE_LIMIT): DataFunction("get_wattage_limit"),
|
||||||
|
str(DataOptions.FANS): DataFunction(
|
||||||
|
"get_fans", [RPCAPICommand("api_stats", "stats")]
|
||||||
|
),
|
||||||
|
str(DataOptions.FAN_PSU): DataFunction("get_fan_psu"),
|
||||||
|
str(DataOptions.ERRORS): DataFunction("get_errors"),
|
||||||
|
str(DataOptions.FAULT_LIGHT): DataFunction("get_fault_light"),
|
||||||
|
str(DataOptions.IS_MINING): DataFunction("is_mining"),
|
||||||
|
str(DataOptions.UPTIME): DataFunction("get_uptime"),
|
||||||
|
str(DataOptions.CONFIG): DataFunction("get_config"),
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class BFGMiner(BaseMiner):
|
class BFGMiner(BaseMiner):
|
||||||
@@ -268,32 +284,6 @@ class BFGMiner(BaseMiner):
|
|||||||
|
|
||||||
return fans
|
return fans
|
||||||
|
|
||||||
async def get_pools(self, api_pools: dict = None) -> List[dict]:
|
|
||||||
groups = []
|
|
||||||
|
|
||||||
if not api_pools:
|
|
||||||
try:
|
|
||||||
api_pools = await self.api.pools()
|
|
||||||
except APIError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if api_pools:
|
|
||||||
try:
|
|
||||||
pools = {}
|
|
||||||
for i, pool in enumerate(api_pools["POOLS"]):
|
|
||||||
pools[f"pool_{i + 1}_url"] = (
|
|
||||||
pool["URL"]
|
|
||||||
.replace("stratum+tcp://", "")
|
|
||||||
.replace("stratum2+tcp://", "")
|
|
||||||
)
|
|
||||||
pools[f"pool_{i + 1}_user"] = pool["User"]
|
|
||||||
pools["quota"] = pool["Quota"] if pool.get("Quota") else "0"
|
|
||||||
|
|
||||||
groups.append(pools)
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
return groups
|
|
||||||
|
|
||||||
async def get_errors(self) -> List[MinerErrorData]:
|
async def get_errors(self) -> List[MinerErrorData]:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|||||||
@@ -20,41 +20,55 @@ from pyasic.data import HashBoard
|
|||||||
from pyasic.errors import APIError
|
from pyasic.errors import APIError
|
||||||
from pyasic.logger import logger
|
from pyasic.logger import logger
|
||||||
from pyasic.miners.backends import BFGMiner
|
from pyasic.miners.backends import BFGMiner
|
||||||
|
from pyasic.miners.base import (
|
||||||
|
DataFunction,
|
||||||
|
DataLocations,
|
||||||
|
DataOptions,
|
||||||
|
RPCAPICommand,
|
||||||
|
WebAPICommand,
|
||||||
|
)
|
||||||
from pyasic.web.goldshell import GoldshellWebAPI
|
from pyasic.web.goldshell import GoldshellWebAPI
|
||||||
|
|
||||||
GOLDSHELL_DATA_LOC = {
|
GOLDSHELL_DATA_LOC = DataLocations(
|
||||||
"mac": {"cmd": "get_mac", "kwargs": {"web_setting": {"web": "setting"}}},
|
**{
|
||||||
"model": {"cmd": "get_model", "kwargs": {}},
|
str(DataOptions.MAC): DataFunction(
|
||||||
"api_ver": {"cmd": "get_api_ver", "kwargs": {"api_version": {"api": "version"}}},
|
"get_mac", [WebAPICommand("web_setting", "setting")]
|
||||||
"fw_ver": {"cmd": "get_fw_ver", "kwargs": {"web_status": {"web": "status"}}},
|
),
|
||||||
"hostname": {"cmd": "get_hostname", "kwargs": {}},
|
str(DataOptions.MODEL): DataFunction("get_model"),
|
||||||
"hashrate": {"cmd": "get_hashrate", "kwargs": {"api_summary": {"api": "summary"}}},
|
str(DataOptions.API_VERSION): DataFunction(
|
||||||
"expected_hashrate": {
|
"get_api_ver", [RPCAPICommand("api_version", "version")]
|
||||||
"cmd": "get_expected_hashrate",
|
),
|
||||||
"kwargs": {"api_stats": {"api": "stats"}},
|
str(DataOptions.FW_VERSION): DataFunction(
|
||||||
},
|
"get_fw_ver", [WebAPICommand("web_status", "status")]
|
||||||
"hashboards": {
|
),
|
||||||
"cmd": "get_hashboards",
|
str(DataOptions.HOSTNAME): DataFunction("get_hostname"),
|
||||||
"kwargs": {
|
str(DataOptions.HASHRATE): DataFunction(
|
||||||
"api_devs": {"api": "devs"},
|
"get_hashrate", [RPCAPICommand("api_summary", "summary")]
|
||||||
"api_devdetails": {"api": "devdetails"},
|
),
|
||||||
},
|
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
|
||||||
},
|
"get_expected_hashrate", [RPCAPICommand("api_stats", "stats")]
|
||||||
"env_temp": {"cmd": "get_env_temp", "kwargs": {}},
|
),
|
||||||
"wattage": {"cmd": "get_wattage", "kwargs": {}},
|
str(DataOptions.HASHBOARDS): DataFunction(
|
||||||
"wattage_limit": {"cmd": "get_wattage_limit", "kwargs": {}},
|
"get_hashboards",
|
||||||
"fans": {"cmd": "get_fans", "kwargs": {"api_stats": {"api": "stats"}}},
|
[
|
||||||
"fan_psu": {"cmd": "get_fan_psu", "kwargs": {}},
|
RPCAPICommand("api_devs", "devs"),
|
||||||
"errors": {"cmd": "get_errors", "kwargs": {}},
|
RPCAPICommand("api_devdetails", "devdetails"),
|
||||||
"fault_light": {"cmd": "get_fault_light", "kwargs": {}},
|
],
|
||||||
"pools": {"cmd": "get_pools", "kwargs": {"api_pools": {"api": "pools"}}},
|
),
|
||||||
"is_mining": {"cmd": "is_mining", "kwargs": {}},
|
str(DataOptions.ENVIRONMENT_TEMP): DataFunction("get_env_temp"),
|
||||||
"uptime": {"cmd": "get_uptime", "kwargs": {}},
|
str(DataOptions.WATTAGE): DataFunction("get_wattage"),
|
||||||
"config": {
|
str(DataOptions.WATTAGE_LIMIT): DataFunction("get_wattage_limit"),
|
||||||
"cmd": "get_config",
|
str(DataOptions.FANS): DataFunction(
|
||||||
"kwargs": {},
|
"get_fans", [RPCAPICommand("api_stats", "stats")]
|
||||||
},
|
),
|
||||||
|
str(DataOptions.FAN_PSU): DataFunction("get_fan_psu"),
|
||||||
|
str(DataOptions.ERRORS): DataFunction("get_errors"),
|
||||||
|
str(DataOptions.FAULT_LIGHT): DataFunction("get_fault_light"),
|
||||||
|
str(DataOptions.IS_MINING): DataFunction("is_mining"),
|
||||||
|
str(DataOptions.UPTIME): DataFunction("get_uptime"),
|
||||||
|
str(DataOptions.CONFIG): DataFunction("get_config"),
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class BFGMinerGoldshell(BFGMiner):
|
class BFGMinerGoldshell(BFGMiner):
|
||||||
|
|||||||
@@ -23,32 +23,50 @@ from pyasic.config import MinerConfig
|
|||||||
from pyasic.data import Fan, HashBoard
|
from pyasic.data import Fan, HashBoard
|
||||||
from pyasic.data.error_codes import MinerErrorData
|
from pyasic.data.error_codes import MinerErrorData
|
||||||
from pyasic.errors import APIError
|
from pyasic.errors import APIError
|
||||||
from pyasic.miners.base import BaseMiner
|
from pyasic.miners.base import (
|
||||||
|
BaseMiner,
|
||||||
|
DataFunction,
|
||||||
|
DataLocations,
|
||||||
|
DataOptions,
|
||||||
|
RPCAPICommand,
|
||||||
|
)
|
||||||
|
|
||||||
BMMINER_DATA_LOC = {
|
BMMINER_DATA_LOC = DataLocations(
|
||||||
"mac": {"cmd": "get_mac", "kwargs": {}},
|
**{
|
||||||
"model": {"cmd": "get_model", "kwargs": {}},
|
str(DataOptions.MAC): DataFunction("get_mac"),
|
||||||
"api_ver": {"cmd": "get_api_ver", "kwargs": {"api_version": {"api": "version"}}},
|
str(DataOptions.MODEL): DataFunction("get_model"),
|
||||||
"fw_ver": {"cmd": "get_fw_ver", "kwargs": {"api_version": {"api": "version"}}},
|
str(DataOptions.API_VERSION): DataFunction(
|
||||||
"hostname": {"cmd": "get_hostname", "kwargs": {}},
|
"get_api_ver", [RPCAPICommand("api_version", "version")]
|
||||||
"hashrate": {"cmd": "get_hashrate", "kwargs": {"api_summary": {"api": "summary"}}},
|
),
|
||||||
"expected_hashrate": {
|
str(DataOptions.FW_VERSION): DataFunction(
|
||||||
"cmd": "get_expected_hashrate",
|
"get_fw_ver", [RPCAPICommand("api_version", "version")]
|
||||||
"kwargs": {"api_stats": {"api": "stats"}},
|
),
|
||||||
},
|
str(DataOptions.HOSTNAME): DataFunction("get_hostname"),
|
||||||
"hashboards": {"cmd": "get_hashboards", "kwargs": {"api_stats": {"api": "stats"}}},
|
str(DataOptions.HASHRATE): DataFunction(
|
||||||
"env_temp": {"cmd": "get_env_temp", "kwargs": {}},
|
"get_hashrate", [RPCAPICommand("api_summary", "summary")]
|
||||||
"wattage": {"cmd": "get_wattage", "kwargs": {}},
|
),
|
||||||
"wattage_limit": {"cmd": "get_wattage_limit", "kwargs": {}},
|
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
|
||||||
"fans": {"cmd": "get_fans", "kwargs": {"api_stats": {"api": "stats"}}},
|
"get_expected_hashrate", [RPCAPICommand("api_stats", "stats")]
|
||||||
"fan_psu": {"cmd": "get_fan_psu", "kwargs": {}},
|
),
|
||||||
"errors": {"cmd": "get_errors", "kwargs": {}},
|
str(DataOptions.HASHBOARDS): DataFunction(
|
||||||
"fault_light": {"cmd": "get_fault_light", "kwargs": {}},
|
"get_hashboards", [RPCAPICommand("api_stats", "stats")]
|
||||||
"pools": {"cmd": "get_pools", "kwargs": {"api_pools": {"api": "pools"}}},
|
),
|
||||||
"is_mining": {"cmd": "is_mining", "kwargs": {}},
|
str(DataOptions.ENVIRONMENT_TEMP): DataFunction("get_env_temp"),
|
||||||
"uptime": {"cmd": "get_uptime", "kwargs": {"api_stats": {"api": "stats"}}},
|
str(DataOptions.WATTAGE): DataFunction("get_wattage"),
|
||||||
"config": {"cmd": "get_config", "kwargs": {}},
|
str(DataOptions.WATTAGE_LIMIT): DataFunction("get_wattage_limit"),
|
||||||
|
str(DataOptions.FANS): DataFunction(
|
||||||
|
"get_fans", [RPCAPICommand("api_stats", "stats")]
|
||||||
|
),
|
||||||
|
str(DataOptions.FAN_PSU): DataFunction("get_fan_psu"),
|
||||||
|
str(DataOptions.ERRORS): DataFunction("get_errors"),
|
||||||
|
str(DataOptions.FAULT_LIGHT): DataFunction("get_fault_light"),
|
||||||
|
str(DataOptions.IS_MINING): DataFunction("is_mining"),
|
||||||
|
str(DataOptions.UPTIME): DataFunction(
|
||||||
|
"get_uptime", [RPCAPICommand("api_stats", "stats")]
|
||||||
|
),
|
||||||
|
str(DataOptions.CONFIG): DataFunction("get_config"),
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class BMMiner(BaseMiner):
|
class BMMiner(BaseMiner):
|
||||||
@@ -315,32 +333,6 @@ class BMMiner(BaseMiner):
|
|||||||
|
|
||||||
return fans
|
return fans
|
||||||
|
|
||||||
async def get_pools(self, api_pools: dict = None) -> List[dict]:
|
|
||||||
groups = []
|
|
||||||
|
|
||||||
if not api_pools:
|
|
||||||
try:
|
|
||||||
api_pools = await self.api.pools()
|
|
||||||
except APIError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if api_pools:
|
|
||||||
try:
|
|
||||||
pools = {}
|
|
||||||
for i, pool in enumerate(api_pools["POOLS"]):
|
|
||||||
pools[f"pool_{i + 1}_url"] = (
|
|
||||||
pool["URL"]
|
|
||||||
.replace("stratum+tcp://", "")
|
|
||||||
.replace("stratum2+tcp://", "")
|
|
||||||
)
|
|
||||||
pools[f"pool_{i + 1}_user"] = pool["User"]
|
|
||||||
pools["quota"] = pool["Quota"] if pool.get("Quota") else "0"
|
|
||||||
|
|
||||||
groups.append(pools)
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
return groups
|
|
||||||
|
|
||||||
async def get_errors(self) -> List[MinerErrorData]:
|
async def get_errors(self) -> List[MinerErrorData]:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|||||||
@@ -27,53 +27,69 @@ from pyasic.config.mining import MiningModePowerTune
|
|||||||
from pyasic.data import Fan, HashBoard
|
from pyasic.data import Fan, HashBoard
|
||||||
from pyasic.data.error_codes import BraiinsOSError, MinerErrorData
|
from pyasic.data.error_codes import BraiinsOSError, MinerErrorData
|
||||||
from pyasic.errors import APIError
|
from pyasic.errors import APIError
|
||||||
from pyasic.miners.base import BaseMiner
|
from pyasic.miners.base import (
|
||||||
|
BaseMiner,
|
||||||
|
DataFunction,
|
||||||
|
DataLocations,
|
||||||
|
DataOptions,
|
||||||
|
GraphQLCommand,
|
||||||
|
RPCAPICommand,
|
||||||
|
WebAPICommand,
|
||||||
|
)
|
||||||
from pyasic.web.bosminer import BOSMinerWebAPI
|
from pyasic.web.bosminer import BOSMinerWebAPI
|
||||||
|
|
||||||
BOSMINER_DATA_LOC = {
|
BOSMINER_DATA_LOC = DataLocations(
|
||||||
"mac": {
|
**{
|
||||||
"cmd": "get_mac",
|
str(DataOptions.MAC): DataFunction(
|
||||||
"kwargs": {
|
"get_mac",
|
||||||
"web_net_conf": {"web": "/cgi-bin/luci/admin/network/iface_status/lan"}
|
[
|
||||||
},
|
WebAPICommand(
|
||||||
},
|
"web_net_conf", "/cgi-bin/luci/admin/network/iface_status/lan"
|
||||||
"model": {"cmd": "get_model", "kwargs": {}},
|
)
|
||||||
"api_ver": {"cmd": "get_api_ver", "kwargs": {"api_version": {"api": "version"}}},
|
],
|
||||||
"fw_ver": {
|
),
|
||||||
"cmd": "get_fw_ver",
|
str(DataOptions.MODEL): DataFunction("get_model"),
|
||||||
"kwargs": {
|
str(DataOptions.API_VERSION): DataFunction(
|
||||||
"graphql_version": {"web": {"bos": {"info": {"version": {"full": None}}}}}
|
"get_api_ver", [RPCAPICommand("api_version", "version")]
|
||||||
},
|
),
|
||||||
},
|
str(DataOptions.FW_VERSION): DataFunction(
|
||||||
"hostname": {
|
"get_fw_ver",
|
||||||
"cmd": "get_hostname",
|
[
|
||||||
"kwargs": {"graphql_hostname": {"web": {"bos": {"hostname": None}}}},
|
GraphQLCommand(
|
||||||
},
|
"graphql_version", {"bos": {"info": {"version": {"full": None}}}}
|
||||||
"hashrate": {
|
)
|
||||||
"cmd": "get_hashrate",
|
],
|
||||||
"kwargs": {
|
),
|
||||||
"api_summary": {"api": "summary"},
|
str(DataOptions.HOSTNAME): DataFunction(
|
||||||
"graphql_hashrate": {
|
"get_hostname",
|
||||||
"web": {
|
[GraphQLCommand("graphql_hostname", {"bos": {"hostname": None}})],
|
||||||
|
),
|
||||||
|
str(DataOptions.HASHRATE): DataFunction(
|
||||||
|
"get_hashrate",
|
||||||
|
[
|
||||||
|
RPCAPICommand("api_summary", "summary"),
|
||||||
|
GraphQLCommand(
|
||||||
|
"graphql_hashrate",
|
||||||
|
{
|
||||||
"bosminer": {
|
"bosminer": {
|
||||||
"info": {"workSolver": {"realHashrate": {"mhs1M": None}}}
|
"info": {"workSolver": {"realHashrate": {"mhs1M": None}}}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
),
|
||||||
},
|
],
|
||||||
},
|
),
|
||||||
"expected_hashrate": {
|
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
|
||||||
"cmd": "get_expected_hashrate",
|
"get_expected_hashrate", [RPCAPICommand("api_devs", "devs")]
|
||||||
"kwargs": {"api_devs": {"api": "devs"}},
|
),
|
||||||
},
|
str(DataOptions.HASHBOARDS): DataFunction(
|
||||||
"hashboards": {
|
"get_hashboards",
|
||||||
"cmd": "get_hashboards",
|
[
|
||||||
"kwargs": {
|
RPCAPICommand("api_temps", "temps"),
|
||||||
"api_temps": {"api": "temps"},
|
RPCAPICommand("api_devdetails", "devdetails"),
|
||||||
"api_devdetails": {"api": "devdetails"},
|
RPCAPICommand("api_devs", "devs"),
|
||||||
"api_devs": {"api": "devs"},
|
GraphQLCommand(
|
||||||
"graphql_boards": {
|
"graphql_boards",
|
||||||
"web": {
|
{
|
||||||
"bosminer": {
|
"bosminer": {
|
||||||
"info": {
|
"info": {
|
||||||
"workSolver": {
|
"workSolver": {
|
||||||
@@ -87,50 +103,54 @@ BOSMINER_DATA_LOC = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
),
|
||||||
},
|
],
|
||||||
},
|
),
|
||||||
"wattage": {
|
str(DataOptions.ENVIRONMENT_TEMP): DataFunction("get_env_temp"),
|
||||||
"cmd": "get_wattage",
|
str(DataOptions.WATTAGE): DataFunction(
|
||||||
"kwargs": {
|
"get_wattage",
|
||||||
"api_tunerstatus": {"api": "tunerstatus"},
|
[
|
||||||
"graphql_wattage": {
|
RPCAPICommand("api_tunerstatus", "tunerstatus"),
|
||||||
"web": {
|
GraphQLCommand(
|
||||||
|
"graphql_wattage",
|
||||||
|
{
|
||||||
"bosminer": {
|
"bosminer": {
|
||||||
"info": {"workSolver": {"power": {"approxConsumptionW": None}}}
|
"info": {
|
||||||
|
"workSolver": {"power": {"approxConsumptionW": None}}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
),
|
||||||
},
|
],
|
||||||
"wattage_limit": {
|
),
|
||||||
"cmd": "get_wattage_limit",
|
str(DataOptions.WATTAGE_LIMIT): DataFunction(
|
||||||
"kwargs": {
|
"get_wattage_limit",
|
||||||
"api_tunerstatus": {"api": "tunerstatus"},
|
[
|
||||||
"graphql_wattage_limit": {
|
RPCAPICommand("api_tunerstatus", "tunerstatus"),
|
||||||
"web": {
|
GraphQLCommand(
|
||||||
"bosminer": {"info": {"workSolver": {"power": {"limitW": None}}}}
|
"graphql_wattage_limit",
|
||||||
}
|
{"bosminer": {"info": {"workSolver": {"power": {"limitW": None}}}}},
|
||||||
},
|
),
|
||||||
},
|
],
|
||||||
},
|
),
|
||||||
"fans": {
|
str(DataOptions.FANS): DataFunction(
|
||||||
"cmd": "get_fans",
|
"get_fans",
|
||||||
"kwargs": {
|
[
|
||||||
"api_fans": {"api": "fans"},
|
RPCAPICommand("api_fans", "fans"),
|
||||||
"graphql_fans": {
|
GraphQLCommand(
|
||||||
"web": {"bosminer": {"info": {"fans": {"name": None, "rpm": None}}}}
|
"graphql_fans",
|
||||||
},
|
{"bosminer": {"info": {"fans": {"name": None, "rpm": None}}}},
|
||||||
},
|
),
|
||||||
},
|
],
|
||||||
"fan_psu": {"cmd": "get_fan_psu", "kwargs": {}},
|
),
|
||||||
"env_temp": {"cmd": "get_env_temp", "kwargs": {}},
|
str(DataOptions.FAN_PSU): DataFunction("get_fan_psu"),
|
||||||
"errors": {
|
str(DataOptions.ERRORS): DataFunction(
|
||||||
"cmd": "get_errors",
|
"get_errors",
|
||||||
"kwargs": {
|
[
|
||||||
"api_tunerstatus": {"api": "tunerstatus"},
|
RPCAPICommand("api_tunerstatus", "tunerstatus"),
|
||||||
"graphql_errors": {
|
GraphQLCommand(
|
||||||
"web": {
|
"graphql_errors",
|
||||||
|
{
|
||||||
"bosminer": {
|
"bosminer": {
|
||||||
"info": {
|
"info": {
|
||||||
"workSolver": {
|
"workSolver": {
|
||||||
@@ -141,43 +161,23 @@ BOSMINER_DATA_LOC = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
str(DataOptions.FAULT_LIGHT): DataFunction(
|
||||||
|
"get_fault_light",
|
||||||
|
[GraphQLCommand("graphql_fault_light", {"bos": {"faultLight": None}})],
|
||||||
|
),
|
||||||
|
str(DataOptions.IS_MINING): DataFunction(
|
||||||
|
"is_mining", [RPCAPICommand("api_devdetails", "devdetails")]
|
||||||
|
),
|
||||||
|
str(DataOptions.UPTIME): DataFunction(
|
||||||
|
"get_uptime", [RPCAPICommand("api_summary", "summary")]
|
||||||
|
),
|
||||||
|
str(DataOptions.CONFIG): DataFunction("get_config"),
|
||||||
}
|
}
|
||||||
},
|
)
|
||||||
},
|
|
||||||
},
|
|
||||||
"fault_light": {
|
|
||||||
"cmd": "get_fault_light",
|
|
||||||
"kwargs": {"graphql_fault_light": {"web": {"bos": {"faultLight": None}}}},
|
|
||||||
},
|
|
||||||
"pools": {
|
|
||||||
"cmd": "get_pools",
|
|
||||||
"kwargs": {
|
|
||||||
"api_pools": {"api": "pools"},
|
|
||||||
"graphql_pools": {
|
|
||||||
"web": {
|
|
||||||
"bosminer": {
|
|
||||||
"config": {
|
|
||||||
"... on BosminerConfig": {
|
|
||||||
"groups": {
|
|
||||||
"pools": {"url": None, "user": None},
|
|
||||||
"strategy": {
|
|
||||||
"... on QuotaStrategy": {"quota": None}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"is_mining": {
|
|
||||||
"cmd": "is_mining",
|
|
||||||
"kwargs": {"api_devdetails": {"api": "devdetails"}},
|
|
||||||
},
|
|
||||||
"uptime": {"cmd": "get_uptime", "kwargs": {"api_summary": {"api": "summary"}}},
|
|
||||||
"config": {"cmd": "get_config", "kwargs": {}},
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class BOSMiner(BaseMiner):
|
class BOSMiner(BaseMiner):
|
||||||
@@ -231,7 +231,6 @@ class BOSMiner(BaseMiner):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
async def fault_light_on(self) -> bool:
|
async def fault_light_on(self) -> bool:
|
||||||
"""Sends command to turn on fault light on the miner."""
|
|
||||||
logging.debug(f"{self}: Sending fault_light on command.")
|
logging.debug(f"{self}: Sending fault_light on command.")
|
||||||
ret = await self.send_ssh_command("miner fault_light on")
|
ret = await self.send_ssh_command("miner fault_light on")
|
||||||
logging.debug(f"{self}: fault_light on command completed.")
|
logging.debug(f"{self}: fault_light on command completed.")
|
||||||
@@ -241,7 +240,6 @@ class BOSMiner(BaseMiner):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
async def fault_light_off(self) -> bool:
|
async def fault_light_off(self) -> bool:
|
||||||
"""Sends command to turn off fault light on the miner."""
|
|
||||||
logging.debug(f"{self}: Sending fault_light off command.")
|
logging.debug(f"{self}: Sending fault_light off command.")
|
||||||
self.light = False
|
self.light = False
|
||||||
ret = await self.send_ssh_command("miner fault_light off")
|
ret = await self.send_ssh_command("miner fault_light off")
|
||||||
@@ -252,11 +250,9 @@ class BOSMiner(BaseMiner):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
async def restart_backend(self) -> bool:
|
async def restart_backend(self) -> bool:
|
||||||
"""Restart bosminer hashing process. Wraps [`restart_bosminer`][pyasic.miners.backends.bosminer.BOSMiner.restart_bosminer] to standardize."""
|
|
||||||
return await self.restart_bosminer()
|
return await self.restart_bosminer()
|
||||||
|
|
||||||
async def restart_bosminer(self) -> bool:
|
async def restart_bosminer(self) -> bool:
|
||||||
"""Restart bosminer hashing process."""
|
|
||||||
logging.debug(f"{self}: Sending bosminer restart command.")
|
logging.debug(f"{self}: Sending bosminer restart command.")
|
||||||
ret = await self.send_ssh_command("/etc/init.d/bosminer restart")
|
ret = await self.send_ssh_command("/etc/init.d/bosminer restart")
|
||||||
logging.debug(f"{self}: bosminer restart command completed.")
|
logging.debug(f"{self}: bosminer restart command completed.")
|
||||||
@@ -285,7 +281,6 @@ class BOSMiner(BaseMiner):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
async def reboot(self) -> bool:
|
async def reboot(self) -> bool:
|
||||||
"""Reboots power to the physical miner."""
|
|
||||||
logging.debug(f"{self}: Sending reboot command.")
|
logging.debug(f"{self}: Sending reboot command.")
|
||||||
ret = await self.send_ssh_command("/sbin/reboot")
|
ret = await self.send_ssh_command("/sbin/reboot")
|
||||||
logging.debug(f"{self}: Reboot command completed.")
|
logging.debug(f"{self}: Reboot command completed.")
|
||||||
@@ -537,7 +532,7 @@ class BOSMiner(BaseMiner):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
try:
|
try:
|
||||||
async with (await self._get_ssh_connection()) as conn:
|
async with await self._get_ssh_connection() as conn:
|
||||||
if conn is not None:
|
if conn is not None:
|
||||||
data = await conn.run("cat /proc/sys/kernel/hostname")
|
data = await conn.run("cat /proc/sys/kernel/hostname")
|
||||||
host = data.stdout.strip()
|
host = data.stdout.strip()
|
||||||
@@ -833,95 +828,6 @@ class BOSMiner(BaseMiner):
|
|||||||
async def get_fan_psu(self) -> Optional[int]:
|
async def get_fan_psu(self) -> Optional[int]:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
async def get_pools(
|
|
||||||
self, api_pools: dict = None, graphql_pools: dict = None
|
|
||||||
) -> List[dict]:
|
|
||||||
if not graphql_pools and not api_pools:
|
|
||||||
try:
|
|
||||||
graphql_pools = await self.web.send_command(
|
|
||||||
{
|
|
||||||
"bosminer": {
|
|
||||||
"config": {
|
|
||||||
"... on BosminerConfig": {
|
|
||||||
"groups": {
|
|
||||||
"pools": {"urluser"},
|
|
||||||
"strategy": {"... on QuotaStrategy": {"quota"}},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
except APIError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if graphql_pools:
|
|
||||||
groups = []
|
|
||||||
try:
|
|
||||||
g = graphql_pools["data"]["bosminer"]["config"]["groups"]
|
|
||||||
for group in g:
|
|
||||||
pools = {"quota": group["strategy"]["quota"]}
|
|
||||||
for i, pool in enumerate(group["pools"]):
|
|
||||||
pools[f"pool_{i + 1}_url"] = (
|
|
||||||
pool["url"]
|
|
||||||
.replace("stratum+tcp://", "")
|
|
||||||
.replace("stratum2+tcp://", "")
|
|
||||||
)
|
|
||||||
pools[f"pool_{i + 1}_user"] = pool["user"]
|
|
||||||
groups.append(pools)
|
|
||||||
return groups
|
|
||||||
except (KeyError, TypeError):
|
|
||||||
pass
|
|
||||||
|
|
||||||
if not api_pools:
|
|
||||||
try:
|
|
||||||
api_pools = await self.api.pools()
|
|
||||||
except APIError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if api_pools:
|
|
||||||
seen = []
|
|
||||||
groups = [{"quota": "0"}]
|
|
||||||
if api_pools.get("POOLS"):
|
|
||||||
for i, pool in enumerate(api_pools["POOLS"]):
|
|
||||||
if len(seen) == 0:
|
|
||||||
seen.append(pool["User"])
|
|
||||||
if not pool["User"] in seen:
|
|
||||||
# need to use get_config, as this will never read perfectly as there are some bad edge cases
|
|
||||||
groups = []
|
|
||||||
cfg = await self.get_config()
|
|
||||||
if cfg:
|
|
||||||
for group in cfg.pool_groups:
|
|
||||||
pools = {"quota": group.quota}
|
|
||||||
for _i, _pool in enumerate(group.pools):
|
|
||||||
pools[f"pool_{_i + 1}_url"] = _pool.url.replace(
|
|
||||||
"stratum+tcp://", ""
|
|
||||||
).replace("stratum2+tcp://", "")
|
|
||||||
pools[f"pool_{_i + 1}_user"] = _pool.username
|
|
||||||
groups.append(pools)
|
|
||||||
return groups
|
|
||||||
else:
|
|
||||||
groups[0][f"pool_{i + 1}_url"] = (
|
|
||||||
pool["URL"]
|
|
||||||
.replace("stratum+tcp://", "")
|
|
||||||
.replace("stratum2+tcp://", "")
|
|
||||||
)
|
|
||||||
groups[0][f"pool_{i + 1}_user"] = pool["User"]
|
|
||||||
else:
|
|
||||||
groups = []
|
|
||||||
cfg = await self.get_config()
|
|
||||||
if cfg:
|
|
||||||
for group in cfg.pool_groups:
|
|
||||||
pools = {"quota": group.quota}
|
|
||||||
for _i, _pool in enumerate(group.pools):
|
|
||||||
pools[f"pool_{_i + 1}_url"] = _pool.url.replace(
|
|
||||||
"stratum+tcp://", ""
|
|
||||||
).replace("stratum2+tcp://", "")
|
|
||||||
pools[f"pool_{_i + 1}_user"] = _pool.username
|
|
||||||
groups.append(pools)
|
|
||||||
return groups
|
|
||||||
return groups
|
|
||||||
|
|
||||||
async def get_errors(
|
async def get_errors(
|
||||||
self, api_tunerstatus: dict = None, graphql_errors: dict = None
|
self, api_tunerstatus: dict = None, graphql_errors: dict = None
|
||||||
) -> List[MinerErrorData]:
|
) -> List[MinerErrorData]:
|
||||||
|
|||||||
@@ -136,9 +136,6 @@ class BOSMinerOld(BOSMiner):
|
|||||||
async def get_fw_ver(self, *args, **kwargs) -> Optional[str]:
|
async def get_fw_ver(self, *args, **kwargs) -> Optional[str]:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
async def get_pools(self, *args, **kwargs) -> List[dict]:
|
|
||||||
return []
|
|
||||||
|
|
||||||
async def get_errors(self, *args, **kwargs) -> List[MinerErrorData]:
|
async def get_errors(self, *args, **kwargs) -> List[MinerErrorData]:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|||||||
@@ -23,74 +23,86 @@ from pyasic.config import MinerConfig, MiningModeConfig
|
|||||||
from pyasic.data import Fan, HashBoard
|
from pyasic.data import Fan, HashBoard
|
||||||
from pyasic.data.error_codes import MinerErrorData, WhatsminerError
|
from pyasic.data.error_codes import MinerErrorData, WhatsminerError
|
||||||
from pyasic.errors import APIError
|
from pyasic.errors import APIError
|
||||||
from pyasic.miners.base import BaseMiner
|
from pyasic.miners.base import (
|
||||||
|
BaseMiner,
|
||||||
|
DataFunction,
|
||||||
|
DataLocations,
|
||||||
|
DataOptions,
|
||||||
|
RPCAPICommand,
|
||||||
|
WebAPICommand,
|
||||||
|
)
|
||||||
|
|
||||||
BTMINER_DATA_LOC = {
|
BTMINER_DATA_LOC = DataLocations(
|
||||||
"mac": {
|
**{
|
||||||
"cmd": "get_mac",
|
str(DataOptions.MAC): DataFunction(
|
||||||
"kwargs": {
|
"get_mac",
|
||||||
"api_summary": {"api": "summary"},
|
[
|
||||||
"api_get_miner_info": {"api": "get_miner_info"},
|
RPCAPICommand("api_summary", "summary"),
|
||||||
},
|
RPCAPICommand("api_get_miner_info", "get_miner_info"),
|
||||||
},
|
],
|
||||||
"model": {"cmd": "get_model", "kwargs": {}},
|
),
|
||||||
"api_ver": {
|
str(DataOptions.MODEL): DataFunction("get_model"),
|
||||||
"cmd": "get_api_ver",
|
str(DataOptions.API_VERSION): DataFunction(
|
||||||
"kwargs": {"api_get_version": {"api": "get_version"}},
|
"get_api_ver", [RPCAPICommand("api_get_version", "get_version")]
|
||||||
},
|
),
|
||||||
"fw_ver": {
|
str(DataOptions.FW_VERSION): DataFunction(
|
||||||
"cmd": "get_fw_ver",
|
"get_fw_ver",
|
||||||
"kwargs": {
|
[
|
||||||
"api_get_version": {"api": "get_version"},
|
RPCAPICommand("api_get_version", "get_version"),
|
||||||
"api_summary": {"api": "summary"},
|
RPCAPICommand("api_summary", "summary"),
|
||||||
},
|
],
|
||||||
},
|
),
|
||||||
"hostname": {
|
str(DataOptions.HOSTNAME): DataFunction(
|
||||||
"cmd": "get_hostname",
|
"get_hostname", [RPCAPICommand("api_get_miner_info", "get_miner_info")]
|
||||||
"kwargs": {"api_get_miner_info": {"api": "get_miner_info"}},
|
),
|
||||||
},
|
str(DataOptions.HASHRATE): DataFunction(
|
||||||
"hashrate": {"cmd": "get_hashrate", "kwargs": {"api_summary": {"api": "summary"}}},
|
"get_hashrate", [RPCAPICommand("api_summary", "summary")]
|
||||||
"expected_hashrate": {
|
),
|
||||||
"cmd": "get_expected_hashrate",
|
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
|
||||||
"kwargs": {"api_summary": {"api": "summary"}},
|
"get_expected_hashrate", [RPCAPICommand("api_summary", "summary")]
|
||||||
},
|
),
|
||||||
"hashboards": {"cmd": "get_hashboards", "kwargs": {"api_devs": {"api": "devs"}}},
|
str(DataOptions.HASHBOARDS): DataFunction(
|
||||||
"env_temp": {"cmd": "get_env_temp", "kwargs": {"api_summary": {"api": "summary"}}},
|
"get_hashboards", [RPCAPICommand("api_devs", "devs")]
|
||||||
"wattage": {"cmd": "get_wattage", "kwargs": {"api_summary": {"api": "summary"}}},
|
),
|
||||||
"wattage_limit": {
|
str(DataOptions.ENVIRONMENT_TEMP): DataFunction(
|
||||||
"cmd": "get_wattage_limit",
|
"get_env_temp", [RPCAPICommand("api_summary", "summary")]
|
||||||
"kwargs": {"api_summary": {"api": "summary"}},
|
),
|
||||||
},
|
str(DataOptions.WATTAGE): DataFunction(
|
||||||
"fans": {
|
"get_wattage", [RPCAPICommand("api_summary", "summary")]
|
||||||
"cmd": "get_fans",
|
),
|
||||||
"kwargs": {
|
str(DataOptions.WATTAGE_LIMIT): DataFunction(
|
||||||
"api_summary": {"api": "summary"},
|
"get_wattage_limit", [RPCAPICommand("api_summary", "summary")]
|
||||||
"api_get_psu": {"api": "get_psu"},
|
),
|
||||||
},
|
str(DataOptions.FANS): DataFunction(
|
||||||
},
|
"get_fans",
|
||||||
"fan_psu": {
|
[
|
||||||
"cmd": "get_fan_psu",
|
RPCAPICommand("api_summary", "summary"),
|
||||||
"kwargs": {
|
RPCAPICommand("api_get_psu", "get_psu"),
|
||||||
"api_summary": {"api": "summary"},
|
],
|
||||||
"api_get_psu": {"api": "get_psu"},
|
),
|
||||||
},
|
str(DataOptions.FAN_PSU): DataFunction(
|
||||||
},
|
"get_fan_psu",
|
||||||
"errors": {
|
[
|
||||||
"cmd": "get_errors",
|
RPCAPICommand("api_summary", "summary"),
|
||||||
"kwargs": {
|
RPCAPICommand("api_get_psu", "get_psu"),
|
||||||
"api_summary": {"api": "summary"},
|
],
|
||||||
"api_get_error_code": {"api": "get_error_code"},
|
),
|
||||||
},
|
str(DataOptions.ERRORS): DataFunction(
|
||||||
},
|
"get_errors", [RPCAPICommand("api_get_error_code", "get_error_code")]
|
||||||
"fault_light": {
|
),
|
||||||
"cmd": "get_fault_light",
|
str(DataOptions.FAULT_LIGHT): DataFunction(
|
||||||
"kwargs": {"api_get_miner_info": {"api": "get_miner_info"}},
|
"get_fault_light",
|
||||||
},
|
[RPCAPICommand("api_get_miner_info", "get_miner_info")],
|
||||||
"pools": {"cmd": "get_pools", "kwargs": {"api_pools": {"api": "pools"}}},
|
),
|
||||||
"is_mining": {"cmd": "is_mining", "kwargs": {"api_status": {"api": "status"}}},
|
str(DataOptions.IS_MINING): DataFunction(
|
||||||
"uptime": {"cmd": "get_uptime", "kwargs": {"api_summary": {"api": "summary"}}},
|
"is_mining", [RPCAPICommand("api_status", "status")]
|
||||||
"config": {"cmd": "get_config", "kwargs": {}},
|
),
|
||||||
|
str(DataOptions.UPTIME): DataFunction(
|
||||||
|
"get_uptime", [RPCAPICommand("api_summary", "summary")]
|
||||||
|
),
|
||||||
|
str(DataOptions.CONFIG): DataFunction("get_config"),
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class BTMiner(BaseMiner):
|
class BTMiner(BaseMiner):
|
||||||
@@ -434,6 +446,7 @@ class BTMiner(BaseMiner):
|
|||||||
float(board["MHS 1m"] / 1000000), 2
|
float(board["MHS 1m"] / 1000000), 2
|
||||||
)
|
)
|
||||||
hashboards[board["ASC"]].chips = board["Effective Chips"]
|
hashboards[board["ASC"]].chips = board["Effective Chips"]
|
||||||
|
hashboards[board["ASC"]].serial_number = board["PCB SN"]
|
||||||
hashboards[board["ASC"]].missing = False
|
hashboards[board["ASC"]].missing = False
|
||||||
except (KeyError, IndexError):
|
except (KeyError, IndexError):
|
||||||
pass
|
pass
|
||||||
@@ -529,32 +542,6 @@ class BTMiner(BaseMiner):
|
|||||||
except (KeyError, TypeError):
|
except (KeyError, TypeError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
async def get_pools(self, api_pools: dict = None) -> List[dict]:
|
|
||||||
groups = []
|
|
||||||
|
|
||||||
if not api_pools:
|
|
||||||
try:
|
|
||||||
api_pools = await self.api.pools()
|
|
||||||
except APIError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if api_pools:
|
|
||||||
try:
|
|
||||||
pools = {}
|
|
||||||
for i, pool in enumerate(api_pools["POOLS"]):
|
|
||||||
pools[f"pool_{i + 1}_url"] = (
|
|
||||||
pool["URL"]
|
|
||||||
.replace("stratum+tcp://", "")
|
|
||||||
.replace("stratum2+tcp://", "")
|
|
||||||
)
|
|
||||||
pools[f"pool_{i + 1}_user"] = pool["User"]
|
|
||||||
pools["quota"] = pool["Quota"] if pool.get("Quota") else "0"
|
|
||||||
|
|
||||||
groups.append(pools)
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
return groups
|
|
||||||
|
|
||||||
async def get_errors(
|
async def get_errors(
|
||||||
self, api_summary: dict = None, api_get_error_code: dict = None
|
self, api_summary: dict = None, api_get_error_code: dict = None
|
||||||
) -> List[MinerErrorData]:
|
) -> List[MinerErrorData]:
|
||||||
@@ -600,8 +587,8 @@ class BTMiner(BaseMiner):
|
|||||||
if api_summary:
|
if api_summary:
|
||||||
try:
|
try:
|
||||||
expected_hashrate = api_summary["SUMMARY"][0]["Factory GHS"]
|
expected_hashrate = api_summary["SUMMARY"][0]["Factory GHS"]
|
||||||
if nominal_hashrate:
|
if expected_hashrate:
|
||||||
return round(nominal_hashrate / 1000, 2)
|
return round(expected_hashrate / 1000, 2)
|
||||||
except (KeyError, IndexError):
|
except (KeyError, IndexError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -23,32 +23,50 @@ from pyasic.config import MinerConfig
|
|||||||
from pyasic.data import Fan, HashBoard
|
from pyasic.data import Fan, HashBoard
|
||||||
from pyasic.data.error_codes import MinerErrorData
|
from pyasic.data.error_codes import MinerErrorData
|
||||||
from pyasic.errors import APIError
|
from pyasic.errors import APIError
|
||||||
from pyasic.miners.base import BaseMiner
|
from pyasic.miners.base import (
|
||||||
|
BaseMiner,
|
||||||
|
DataFunction,
|
||||||
|
DataLocations,
|
||||||
|
DataOptions,
|
||||||
|
RPCAPICommand,
|
||||||
|
)
|
||||||
|
|
||||||
CGMINER_DATA_LOC = {
|
CGMINER_DATA_LOC = DataLocations(
|
||||||
"mac": {"cmd": "get_mac", "kwargs": {}},
|
**{
|
||||||
"model": {"cmd": "get_model", "kwargs": {}},
|
str(DataOptions.MAC): DataFunction("get_mac"),
|
||||||
"api_ver": {"cmd": "get_api_ver", "kwargs": {"api_version": {"api": "version"}}},
|
str(DataOptions.MODEL): DataFunction("get_model"),
|
||||||
"fw_ver": {"cmd": "get_fw_ver", "kwargs": {"api_version": {"api": "version"}}},
|
str(DataOptions.API_VERSION): DataFunction(
|
||||||
"hostname": {"cmd": "get_hostname", "kwargs": {}},
|
"get_api_ver", [RPCAPICommand("api_version", "version")]
|
||||||
"hashrate": {"cmd": "get_hashrate", "kwargs": {"api_summary": {"api": "summary"}}},
|
),
|
||||||
"expected_hashrate": {
|
str(DataOptions.FW_VERSION): DataFunction(
|
||||||
"cmd": "get_expected_hashrate",
|
"get_fw_ver", [RPCAPICommand("api_version", "version")]
|
||||||
"kwargs": {"api_stats": {"api": "stats"}},
|
),
|
||||||
},
|
str(DataOptions.HOSTNAME): DataFunction("get_hostname"),
|
||||||
"hashboards": {"cmd": "get_hashboards", "kwargs": {"api_stats": {"api": "stats"}}},
|
str(DataOptions.HASHRATE): DataFunction(
|
||||||
"env_temp": {"cmd": "get_env_temp", "kwargs": {}},
|
"get_hashrate", [RPCAPICommand("api_summary", "summary")]
|
||||||
"wattage": {"cmd": "get_wattage", "kwargs": {}},
|
),
|
||||||
"wattage_limit": {"cmd": "get_wattage_limit", "kwargs": {}},
|
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
|
||||||
"fans": {"cmd": "get_fans", "kwargs": {"api_stats": {"api": "stats"}}},
|
"get_expected_hashrate", [RPCAPICommand("api_stats", "stats")]
|
||||||
"fan_psu": {"cmd": "get_fan_psu", "kwargs": {}},
|
),
|
||||||
"errors": {"cmd": "get_errors", "kwargs": {}},
|
str(DataOptions.HASHBOARDS): DataFunction(
|
||||||
"fault_light": {"cmd": "get_fault_light", "kwargs": {}},
|
"get_hashboards", [RPCAPICommand("api_stats", "stats")]
|
||||||
"pools": {"cmd": "get_pools", "kwargs": {"api_pools": {"api": "pools"}}},
|
),
|
||||||
"is_mining": {"cmd": "is_mining", "kwargs": {}},
|
str(DataOptions.ENVIRONMENT_TEMP): DataFunction("get_env_temp"),
|
||||||
"uptime": {"cmd": "get_uptime", "kwargs": {"api_stats": {"api": "stats"}}},
|
str(DataOptions.WATTAGE): DataFunction("get_wattage"),
|
||||||
"config": {"cmd": "get_config", "kwargs": {}},
|
str(DataOptions.WATTAGE_LIMIT): DataFunction("get_wattage_limit"),
|
||||||
|
str(DataOptions.FANS): DataFunction(
|
||||||
|
"get_fans", [RPCAPICommand("api_stats", "stats")]
|
||||||
|
),
|
||||||
|
str(DataOptions.FAN_PSU): DataFunction("get_fan_psu"),
|
||||||
|
str(DataOptions.ERRORS): DataFunction("get_errors"),
|
||||||
|
str(DataOptions.FAULT_LIGHT): DataFunction("get_fault_light"),
|
||||||
|
str(DataOptions.IS_MINING): DataFunction("is_mining"),
|
||||||
|
str(DataOptions.UPTIME): DataFunction(
|
||||||
|
"get_uptime", [RPCAPICommand("api_stats", "stats")]
|
||||||
|
),
|
||||||
|
str(DataOptions.CONFIG): DataFunction("get_config"),
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class CGMiner(BaseMiner):
|
class CGMiner(BaseMiner):
|
||||||
@@ -94,11 +112,9 @@ class CGMiner(BaseMiner):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
async def restart_backend(self) -> bool:
|
async def restart_backend(self) -> bool:
|
||||||
"""Restart cgminer hashing process. Wraps [`restart_cgminer`][pyasic.miners.backends.cgminer.CGMiner.restart_cgminer] to standardize."""
|
|
||||||
return await self.restart_cgminer()
|
return await self.restart_cgminer()
|
||||||
|
|
||||||
async def restart_cgminer(self) -> bool:
|
async def restart_cgminer(self) -> bool:
|
||||||
"""Restart cgminer hashing process."""
|
|
||||||
commands = ["cgminer-api restart", "/usr/bin/cgminer-monitor >/dev/null 2>&1"]
|
commands = ["cgminer-api restart", "/usr/bin/cgminer-monitor >/dev/null 2>&1"]
|
||||||
commands = ";".join(commands)
|
commands = ";".join(commands)
|
||||||
ret = await self.send_ssh_command(commands)
|
ret = await self.send_ssh_command(commands)
|
||||||
@@ -107,7 +123,6 @@ class CGMiner(BaseMiner):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
async def reboot(self) -> bool:
|
async def reboot(self) -> bool:
|
||||||
"""Reboots power to the physical miner."""
|
|
||||||
logging.debug(f"{self}: Sending reboot command.")
|
logging.debug(f"{self}: Sending reboot command.")
|
||||||
ret = await self.send_ssh_command("reboot")
|
ret = await self.send_ssh_command("reboot")
|
||||||
if ret is None:
|
if ret is None:
|
||||||
@@ -328,32 +343,6 @@ class CGMiner(BaseMiner):
|
|||||||
async def get_fan_psu(self) -> Optional[int]:
|
async def get_fan_psu(self) -> Optional[int]:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
async def get_pools(self, api_pools: dict = None) -> List[dict]:
|
|
||||||
groups = []
|
|
||||||
|
|
||||||
if not api_pools:
|
|
||||||
try:
|
|
||||||
api_pools = await self.api.pools()
|
|
||||||
except APIError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if api_pools:
|
|
||||||
try:
|
|
||||||
pools = {}
|
|
||||||
for i, pool in enumerate(api_pools["POOLS"]):
|
|
||||||
pools[f"pool_{i + 1}_url"] = (
|
|
||||||
pool["URL"]
|
|
||||||
.replace("stratum+tcp://", "")
|
|
||||||
.replace("stratum2+tcp://", "")
|
|
||||||
)
|
|
||||||
pools[f"pool_{i + 1}_user"] = pool["User"]
|
|
||||||
pools["quota"] = pool["Quota"] if pool.get("Quota") else "0"
|
|
||||||
|
|
||||||
groups.append(pools)
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
return groups
|
|
||||||
|
|
||||||
async def get_errors(self) -> List[MinerErrorData]:
|
async def get_errors(self) -> List[MinerErrorData]:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|||||||
@@ -23,37 +23,52 @@ from pyasic.data import Fan, HashBoard
|
|||||||
from pyasic.data.error_codes import MinerErrorData
|
from pyasic.data.error_codes import MinerErrorData
|
||||||
from pyasic.errors import APIError
|
from pyasic.errors import APIError
|
||||||
from pyasic.miners.backends import CGMiner
|
from pyasic.miners.backends import CGMiner
|
||||||
|
from pyasic.miners.base import DataFunction, DataLocations, DataOptions, RPCAPICommand
|
||||||
|
|
||||||
AVALON_DATA_LOC = {
|
AVALON_DATA_LOC = DataLocations(
|
||||||
"mac": {"cmd": "get_mac", "kwargs": {"api_version": {"api": "version"}}},
|
**{
|
||||||
"model": {"cmd": "get_model", "kwargs": {}},
|
str(DataOptions.MAC): DataFunction(
|
||||||
"api_ver": {"cmd": "get_api_ver", "kwargs": {"api_version": {"api": "version"}}},
|
"get_mac", [RPCAPICommand("api_version", "version")]
|
||||||
"fw_ver": {"cmd": "get_fw_ver", "kwargs": {"api_version": {"api": "version"}}},
|
),
|
||||||
"hostname": {"cmd": "get_hostname", "kwargs": {"mac": {"api": "version"}}},
|
str(DataOptions.MODEL): DataFunction("get_model"),
|
||||||
"hashrate": {"cmd": "get_hashrate", "kwargs": {"api_devs": {"api": "devs"}}},
|
str(DataOptions.API_VERSION): DataFunction(
|
||||||
"expected_hashrate": {
|
"get_api_ver", [RPCAPICommand("api_version", "version")]
|
||||||
"cmd": "get_expected_hashrate",
|
),
|
||||||
"kwargs": {"api_stats": {"api": "stats"}},
|
str(DataOptions.FW_VERSION): DataFunction(
|
||||||
},
|
"get_fw_ver", [RPCAPICommand("api_version", "version")]
|
||||||
"hashboards": {"cmd": "get_hashboards", "kwargs": {"api_stats": {"api": "stats"}}},
|
),
|
||||||
"env_temp": {"cmd": "get_env_temp", "kwargs": {"api_stats": {"api": "stats"}}},
|
str(DataOptions.HOSTNAME): DataFunction(
|
||||||
"wattage": {"cmd": "get_wattage", "kwargs": {}},
|
"get_hostname", [RPCAPICommand("api_version", "version")]
|
||||||
"wattage_limit": {
|
),
|
||||||
"cmd": "get_wattage_limit",
|
str(DataOptions.HASHRATE): DataFunction(
|
||||||
"kwargs": {"api_stats": {"api": "stats"}},
|
"get_hashrate", [RPCAPICommand("api_devs", "devs")]
|
||||||
},
|
),
|
||||||
"fans": {"cmd": "get_fans", "kwargs": {"api_stats": {"api": "stats"}}},
|
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
|
||||||
"fan_psu": {"cmd": "get_fan_psu", "kwargs": {}},
|
"get_expected_hashrate", [RPCAPICommand("api_stats", "stats")]
|
||||||
"errors": {"cmd": "get_errors", "kwargs": {}},
|
),
|
||||||
"fault_light": {
|
str(DataOptions.HASHBOARDS): DataFunction(
|
||||||
"cmd": "get_fault_light",
|
"get_hashboards", [RPCAPICommand("api_stats", "stats")]
|
||||||
"kwargs": {"api_stats": {"api": "stats"}},
|
),
|
||||||
},
|
str(DataOptions.ENVIRONMENT_TEMP): DataFunction(
|
||||||
"pools": {"cmd": "get_pools", "kwargs": {"api_pools": {"api": "pools"}}},
|
"get_env_temp", [RPCAPICommand("api_stats", "stats")]
|
||||||
"is_mining": {"cmd": "is_mining", "kwargs": {}},
|
),
|
||||||
"uptime": {"cmd": "get_uptime", "kwargs": {}},
|
str(DataOptions.WATTAGE): DataFunction("get_wattage"),
|
||||||
"config": {"cmd": "get_config", "kwargs": {}},
|
str(DataOptions.WATTAGE_LIMIT): DataFunction(
|
||||||
|
"get_wattage_limit", [RPCAPICommand("api_stats", "stats")]
|
||||||
|
),
|
||||||
|
str(DataOptions.FANS): DataFunction(
|
||||||
|
"get_fans", [RPCAPICommand("api_stats", "stats")]
|
||||||
|
),
|
||||||
|
str(DataOptions.FAN_PSU): DataFunction("get_fan_psu"),
|
||||||
|
str(DataOptions.ERRORS): DataFunction("get_errors"),
|
||||||
|
str(DataOptions.FAULT_LIGHT): DataFunction(
|
||||||
|
"get_fault_light", [RPCAPICommand("api_stats", "stats")]
|
||||||
|
),
|
||||||
|
str(DataOptions.IS_MINING): DataFunction("is_mining"),
|
||||||
|
str(DataOptions.UPTIME): DataFunction("get_uptime"),
|
||||||
|
str(DataOptions.CONFIG): DataFunction("get_config"),
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class CGMinerAvalon(CGMiner):
|
class CGMinerAvalon(CGMiner):
|
||||||
@@ -116,7 +131,7 @@ class CGMinerAvalon(CGMiner):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def parse_stats(stats):
|
def parse_stats(stats):
|
||||||
_stats_items = re.findall(".+?\[*?]", stats)
|
_stats_items = re.findall(".+?\\[*?]", stats)
|
||||||
stats_items = []
|
stats_items = []
|
||||||
stats_dict = {}
|
stats_dict = {}
|
||||||
for item in _stats_items:
|
for item in _stats_items:
|
||||||
@@ -318,32 +333,6 @@ class CGMinerAvalon(CGMiner):
|
|||||||
pass
|
pass
|
||||||
return fans_data
|
return fans_data
|
||||||
|
|
||||||
async def get_pools(self, api_pools: dict = None) -> List[dict]:
|
|
||||||
groups = []
|
|
||||||
|
|
||||||
if not api_pools:
|
|
||||||
try:
|
|
||||||
api_pools = await self.api.pools()
|
|
||||||
except APIError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if api_pools:
|
|
||||||
try:
|
|
||||||
pools = {}
|
|
||||||
for i, pool in enumerate(api_pools["POOLS"]):
|
|
||||||
pools[f"pool_{i + 1}_url"] = (
|
|
||||||
pool["URL"]
|
|
||||||
.replace("stratum+tcp://", "")
|
|
||||||
.replace("stratum2+tcp://", "")
|
|
||||||
)
|
|
||||||
pools[f"pool_{i + 1}_user"] = pool["User"]
|
|
||||||
pools["quota"] = pool["Quota"] if pool.get("Quota") else "0"
|
|
||||||
|
|
||||||
groups.append(pools)
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
return groups
|
|
||||||
|
|
||||||
async def get_errors(self) -> List[MinerErrorData]:
|
async def get_errors(self) -> List[MinerErrorData]:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|||||||
@@ -14,51 +14,74 @@
|
|||||||
# limitations under the License. -
|
# limitations under the License. -
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from typing import List, Optional, Tuple, Union
|
from typing import List, Optional, Tuple
|
||||||
|
|
||||||
|
from pyasic import MinerConfig
|
||||||
from pyasic.data import Fan, HashBoard
|
from pyasic.data import Fan, HashBoard
|
||||||
from pyasic.data.error_codes import MinerErrorData, X19Error
|
from pyasic.data.error_codes import MinerErrorData, X19Error
|
||||||
|
from pyasic.config import MinerConfig, MiningModeConfig
|
||||||
from pyasic.errors import APIError
|
from pyasic.errors import APIError
|
||||||
from pyasic.logger import logger
|
from pyasic.logger import logger
|
||||||
from pyasic.miners.backends.bmminer import BMMiner
|
from pyasic.miners.base import (
|
||||||
|
BaseMiner,
|
||||||
|
DataFunction,
|
||||||
|
DataLocations,
|
||||||
|
DataOptions,
|
||||||
|
WebAPICommand,
|
||||||
|
)
|
||||||
from pyasic.web.epic import ePICWebAPI
|
from pyasic.web.epic import ePICWebAPI
|
||||||
|
|
||||||
EPIC_DATA_LOC = {
|
EPIC_DATA_LOC = DataLocations(
|
||||||
"mac": {"cmd": "get_mac", "kwargs": {"web_summary": {"web": "network"}}},
|
**{
|
||||||
"model": {"cmd": "get_model", "kwargs": {}},
|
str(DataOptions.MAC): DataFunction(
|
||||||
"api_ver": {"cmd": "get_api_ver", "kwargs": {"api_version": {"api": "version"}}},
|
"get_mac", [WebAPICommand("web_network", "network")]
|
||||||
"fw_ver": {"cmd": "get_fw_ver", "kwargs": {"web_summary": {"web": "summary"}}},
|
),
|
||||||
"hostname": {"cmd": "get_hostname", "kwargs": {"web_summary": {"web": "summary"}}},
|
str(DataOptions.MODEL): DataFunction("get_model"),
|
||||||
"hashrate": {"cmd": "get_hashrate", "kwargs": {"web_summary": {"web": "summary"}}},
|
str(DataOptions.API_VERSION): DataFunction("get_api_ver"),
|
||||||
"expected_hashrate": {
|
str(DataOptions.FW_VERSION): DataFunction(
|
||||||
"cmd": "get_nominal_hashrate",
|
"get_fw_ver", [WebAPICommand("web_summary", "summary")]
|
||||||
"kwargs": {"web_summary": {"web": "summary"}},
|
),
|
||||||
},
|
str(DataOptions.HOSTNAME): DataFunction(
|
||||||
"hashboards": {
|
"get_hostname", [WebAPICommand("web_summary", "summary")]
|
||||||
"cmd": "get_hashboards",
|
),
|
||||||
"kwargs": {
|
str(DataOptions.HASHRATE): DataFunction(
|
||||||
"web_summary": {"web": "summary"},
|
"get_hashrate", [WebAPICommand("web_summary", "summary")]
|
||||||
"web_hashrate": {"web": "hashrate"},
|
),
|
||||||
},
|
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
|
||||||
},
|
"get_expected_hashrate", [WebAPICommand("web_summary", "summary")]
|
||||||
"env_temp": {"cmd": "get_env_temp", "kwargs": {}},
|
),
|
||||||
"wattage": {"cmd": "get_wattage", "kwargs": {"web_summary": {"web": "summary"}}},
|
str(DataOptions.HASHBOARDS): DataFunction(
|
||||||
"wattage_limit": {"cmd": "get_wattage_limit", "kwargs": {}},
|
"get_hashboards",
|
||||||
"fans": {"cmd": "get_fans", "kwargs": {"web_summary": {"web": "summary"}}},
|
[
|
||||||
"fan_psu": {"cmd": "get_fan_psu", "kwargs": {}},
|
WebAPICommand("web_summary", "summary"),
|
||||||
"fault_light": {
|
WebAPICommand("web_hashrate", "hashrate"),
|
||||||
"cmd": "get_fault_light",
|
],
|
||||||
"kwargs": {"web_summary": {"web": "summary"}},
|
),
|
||||||
},
|
str(DataOptions.ENVIRONMENT_TEMP): DataFunction("get_env_temp"),
|
||||||
"pools": {"cmd": "get_pools", "kwargs": {"web_summary": {"web": "summary"}}},
|
str(DataOptions.WATTAGE): DataFunction(
|
||||||
"is_mining": {"cmd": "is_mining", "kwargs": {}},
|
"get_wattage", [WebAPICommand("web_summary", "summary")]
|
||||||
"uptime": {"cmd": "get_uptime", "kwargs": {"web_summary": {"web": "summary"}}},
|
),
|
||||||
"errors": {"cmd": "get_errors", "kwargs": {"web_summary": {"web": "summary"}}},
|
str(DataOptions.WATTAGE_LIMIT): DataFunction("get_wattage_limit"),
|
||||||
"config": {"cmd": "get_config", "kwargs": {}},
|
str(DataOptions.FANS): DataFunction(
|
||||||
|
"get_fans", [WebAPICommand("web_summary", "summary")]
|
||||||
|
),
|
||||||
|
str(DataOptions.FAN_PSU): DataFunction("get_fan_psu"),
|
||||||
|
str(DataOptions.ERRORS): DataFunction(
|
||||||
|
"get_errors", [WebAPICommand("web_summary", "summary")]
|
||||||
|
),
|
||||||
|
str(DataOptions.FAULT_LIGHT): DataFunction(
|
||||||
|
"get_fault_light", [WebAPICommand("web_summary", "summary")]
|
||||||
|
),
|
||||||
|
str(DataOptions.IS_MINING): DataFunction("is_mining"),
|
||||||
|
str(DataOptions.UPTIME): DataFunction(
|
||||||
|
"get_uptime", [WebAPICommand("web_summary", "summary")]
|
||||||
|
),
|
||||||
|
str(DataOptions.CONFIG): DataFunction("get_config"),
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ePIC(BMMiner):
|
class ePIC(BaseMiner):
|
||||||
def __init__(self, ip: str, api_ver: str = "0.0.0") -> None:
|
def __init__(self, ip: str, api_ver: str = "0.0.0") -> None:
|
||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
# interfaces
|
# interfaces
|
||||||
@@ -74,6 +97,23 @@ class ePIC(BMMiner):
|
|||||||
return self.model + " (ePIC)"
|
return self.model + " (ePIC)"
|
||||||
return "? (ePIC)"
|
return "? (ePIC)"
|
||||||
|
|
||||||
|
async def get_config(self) -> MinerConfig:
|
||||||
|
summary = None
|
||||||
|
try:
|
||||||
|
summary = await self.web.summary()
|
||||||
|
except APIError as e:
|
||||||
|
logger.warning(e)
|
||||||
|
except LookupError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if summary is not None:
|
||||||
|
cfg = MinerConfig.from_epic(summary)
|
||||||
|
else:
|
||||||
|
cfg = MinerConfig()
|
||||||
|
|
||||||
|
self.config = cfg
|
||||||
|
return self.config
|
||||||
|
|
||||||
async def restart_backend(self) -> bool:
|
async def restart_backend(self) -> bool:
|
||||||
data = await self.web.restart_epic()
|
data = await self.web.restart_epic()
|
||||||
if data:
|
if data:
|
||||||
@@ -110,13 +150,13 @@ class ePIC(BMMiner):
|
|||||||
pass
|
pass
|
||||||
return False
|
return False
|
||||||
|
|
||||||
async def get_mac(self, web_summary: dict = None) -> str:
|
async def get_mac(self, web_network: dict = None) -> str:
|
||||||
if not web_summary:
|
if not web_network:
|
||||||
web_summary = await self.web.network()
|
web_network = await self.web.network()
|
||||||
if web_summary:
|
if web_network:
|
||||||
try:
|
try:
|
||||||
for network in web_summary:
|
for network in web_network:
|
||||||
mac = web_summary[network]["mac_address"]
|
mac = web_network[network]["mac_address"]
|
||||||
return mac
|
return mac
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
@@ -249,32 +289,6 @@ class ePIC(BMMiner):
|
|||||||
async def is_mining(self, *args, **kwargs) -> Optional[bool]:
|
async def is_mining(self, *args, **kwargs) -> Optional[bool]:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
async def get_pools(self, web_summary: dict = None) -> List[dict]:
|
|
||||||
groups = []
|
|
||||||
|
|
||||||
if not web_summary:
|
|
||||||
try:
|
|
||||||
web_summary = await self.api.summary()
|
|
||||||
except APIError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if web_summary:
|
|
||||||
try:
|
|
||||||
pools = {}
|
|
||||||
for i, pool in enumerate(web_summary["StratumConfigs"]):
|
|
||||||
pools[f"pool_{i + 1}_url"] = (
|
|
||||||
pool["pool"]
|
|
||||||
.replace("stratum+tcp://", "")
|
|
||||||
.replace("stratum2+tcp://", "")
|
|
||||||
)
|
|
||||||
pools[f"pool_{i + 1}_user"] = pool["login"]
|
|
||||||
pools["quota"] = pool["Quota"] if pool.get("Quota") else "0"
|
|
||||||
|
|
||||||
groups.append(pools)
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
return groups
|
|
||||||
|
|
||||||
async def get_uptime(self, web_summary: dict = None) -> Optional[int]:
|
async def get_uptime(self, web_summary: dict = None) -> Optional[int]:
|
||||||
if not web_summary:
|
if not web_summary:
|
||||||
web_summary = await self.web.summary()
|
web_summary = await self.web.summary()
|
||||||
@@ -310,3 +324,33 @@ class ePIC(BMMiner):
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
return errors
|
return errors
|
||||||
|
|
||||||
|
def fault_light_off(self) -> bool:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def fault_light_on(self) -> bool:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_api_ver(self, *args, **kwargs) -> Optional[str]:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_config(self) -> MinerConfig:
|
||||||
|
return self.config
|
||||||
|
|
||||||
|
def get_env_temp(self, *args, **kwargs) -> Optional[float]:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_fan_psu(self, *args, **kwargs) -> Optional[int]:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_version(self, *args, **kwargs) -> Tuple[Optional[str], Optional[str]]:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_wattage_limit(self, *args, **kwargs) -> Optional[int]:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def send_config(self, config: MinerConfig, user_suffix: str = None) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def set_power_limit(self, wattage: int) -> bool:
|
||||||
|
return False
|
||||||
|
|||||||
@@ -26,30 +26,52 @@ from pyasic.config import MinerConfig
|
|||||||
from pyasic.data import Fan, HashBoard
|
from pyasic.data import Fan, HashBoard
|
||||||
from pyasic.data.error_codes import BraiinsOSError, MinerErrorData
|
from pyasic.data.error_codes import BraiinsOSError, MinerErrorData
|
||||||
from pyasic.errors import APIError
|
from pyasic.errors import APIError
|
||||||
from pyasic.miners.base import BaseMiner
|
from pyasic.miners.base import (
|
||||||
|
BaseMiner,
|
||||||
|
DataFunction,
|
||||||
|
DataLocations,
|
||||||
|
DataOptions,
|
||||||
|
RPCAPICommand,
|
||||||
|
WebAPICommand,
|
||||||
|
)
|
||||||
from pyasic.web.bosminer import BOSMinerWebAPI
|
from pyasic.web.bosminer import BOSMinerWebAPI
|
||||||
|
|
||||||
LUXMINER_DATA_LOC = {
|
LUXMINER_DATA_LOC = DataLocations(
|
||||||
"mac": {"cmd": "get_mac", "kwargs": {"api_config": {"api": "config"}}},
|
**{
|
||||||
"model": {"cmd": "get_model", "kwargs": {}},
|
str(DataOptions.MAC): DataFunction(
|
||||||
"api_ver": {"cmd": "get_api_ver", "kwargs": {}},
|
"get_mac", [RPCAPICommand("api_config", "config")]
|
||||||
"fw_ver": {"cmd": "get_fw_ver", "kwargs": {}},
|
),
|
||||||
"hostname": {"cmd": "get_hostname", "kwargs": {}},
|
str(DataOptions.MODEL): DataFunction("get_model"),
|
||||||
"hashrate": {"cmd": "get_hashrate", "kwargs": {}},
|
str(DataOptions.API_VERSION): DataFunction("get_api_ver"),
|
||||||
"expected_hashrate": {"cmd": "get_nominal_hashrate", "kwargs": {}},
|
str(DataOptions.FW_VERSION): DataFunction("get_fw_ver"),
|
||||||
"hashboards": {"cmd": "get_hashboards", "kwargs": {}},
|
str(DataOptions.HOSTNAME): DataFunction("get_hostname"),
|
||||||
"wattage": {"cmd": "get_wattage", "kwargs": {}},
|
str(DataOptions.HASHRATE): DataFunction(
|
||||||
"wattage_limit": {"cmd": "get_wattage_limit", "kwargs": {}},
|
"get_hashrate", [RPCAPICommand("api_summary", "summary")]
|
||||||
"fans": {"cmd": "get_fans", "kwargs": {}},
|
),
|
||||||
"fan_psu": {"cmd": "get_fan_psu", "kwargs": {}},
|
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
|
||||||
"env_temp": {"cmd": "get_env_temp", "kwargs": {}},
|
"get_expected_hashrate", [RPCAPICommand("api_stats", "stats")]
|
||||||
"errors": {"cmd": "get_errors", "kwargs": {}},
|
),
|
||||||
"fault_light": {"cmd": "get_fault_light", "kwargs": {}},
|
str(DataOptions.HASHBOARDS): DataFunction(
|
||||||
"pools": {"cmd": "get_pools", "kwargs": {}},
|
"get_hashboards", [RPCAPICommand("api_stats", "stats")]
|
||||||
"is_mining": {"cmd": "is_mining", "kwargs": {}},
|
),
|
||||||
"uptime": {"cmd": "get_uptime", "kwargs": {"api_stats": {"api": "stats"}}},
|
str(DataOptions.ENVIRONMENT_TEMP): DataFunction("get_env_temp"),
|
||||||
"config": {"cmd": "get_config", "kwargs": {}},
|
str(DataOptions.WATTAGE): DataFunction(
|
||||||
|
"get_wattage", [RPCAPICommand("api_power", "power")]
|
||||||
|
),
|
||||||
|
str(DataOptions.WATTAGE_LIMIT): DataFunction("get_wattage_limit"),
|
||||||
|
str(DataOptions.FANS): DataFunction(
|
||||||
|
"get_fans", [RPCAPICommand("api_fans", "fans")]
|
||||||
|
),
|
||||||
|
str(DataOptions.FAN_PSU): DataFunction("get_fan_psu"),
|
||||||
|
str(DataOptions.ERRORS): DataFunction("get_errors"),
|
||||||
|
str(DataOptions.FAULT_LIGHT): DataFunction("get_fault_light"),
|
||||||
|
str(DataOptions.IS_MINING): DataFunction("is_mining"),
|
||||||
|
str(DataOptions.UPTIME): DataFunction(
|
||||||
|
"get_uptime", [RPCAPICommand("api_stats", "stats")]
|
||||||
|
),
|
||||||
|
str(DataOptions.CONFIG): DataFunction("get_config"),
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class LUXMiner(BaseMiner):
|
class LUXMiner(BaseMiner):
|
||||||
@@ -85,7 +107,6 @@ class LUXMiner(BaseMiner):
|
|||||||
return
|
return
|
||||||
|
|
||||||
async def fault_light_on(self) -> bool:
|
async def fault_light_on(self) -> bool:
|
||||||
"""Sends command to turn on fault light on the miner."""
|
|
||||||
try:
|
try:
|
||||||
session_id = await self._get_session()
|
session_id = await self._get_session()
|
||||||
if session_id:
|
if session_id:
|
||||||
@@ -96,7 +117,6 @@ class LUXMiner(BaseMiner):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
async def fault_light_off(self) -> bool:
|
async def fault_light_off(self) -> bool:
|
||||||
"""Sends command to turn off fault light on the miner."""
|
|
||||||
try:
|
try:
|
||||||
session_id = await self._get_session()
|
session_id = await self._get_session()
|
||||||
if session_id:
|
if session_id:
|
||||||
@@ -107,11 +127,9 @@ class LUXMiner(BaseMiner):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
async def restart_backend(self) -> bool:
|
async def restart_backend(self) -> bool:
|
||||||
"""Restart luxminer hashing process. Wraps [`restart_luxminer`][pyasic.miners.backends.luxminer.LUXMiner.restart_luxminer] to standardize."""
|
|
||||||
return await self.restart_luxminer()
|
return await self.restart_luxminer()
|
||||||
|
|
||||||
async def restart_luxminer(self) -> bool:
|
async def restart_luxminer(self) -> bool:
|
||||||
"""Restart luxminer hashing process."""
|
|
||||||
try:
|
try:
|
||||||
session_id = await self._get_session()
|
session_id = await self._get_session()
|
||||||
if session_id:
|
if session_id:
|
||||||
@@ -141,7 +159,6 @@ class LUXMiner(BaseMiner):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
async def reboot(self) -> bool:
|
async def reboot(self) -> bool:
|
||||||
"""Reboots power to the physical miner."""
|
|
||||||
try:
|
try:
|
||||||
session_id = await self._get_session()
|
session_id = await self._get_session()
|
||||||
if session_id:
|
if session_id:
|
||||||
@@ -303,56 +320,6 @@ class LUXMiner(BaseMiner):
|
|||||||
async def get_fan_psu(self) -> Optional[int]:
|
async def get_fan_psu(self) -> Optional[int]:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
async def get_pools(self, api_pools: dict = None) -> List[dict]:
|
|
||||||
if not api_pools:
|
|
||||||
try:
|
|
||||||
api_pools = await self.api.pools()
|
|
||||||
except APIError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if api_pools:
|
|
||||||
seen = []
|
|
||||||
groups = [{"quota": "0"}]
|
|
||||||
if api_pools.get("POOLS"):
|
|
||||||
for i, pool in enumerate(api_pools["POOLS"]):
|
|
||||||
if len(seen) == 0:
|
|
||||||
seen.append(pool["User"])
|
|
||||||
if not pool["User"] in seen:
|
|
||||||
# need to use get_config, as this will never read perfectly as there are some bad edge cases
|
|
||||||
groups = []
|
|
||||||
cfg = await self.get_config()
|
|
||||||
if cfg:
|
|
||||||
for group in cfg.pool_groups:
|
|
||||||
pools = {"quota": group.quota}
|
|
||||||
for _i, _pool in enumerate(group.pools):
|
|
||||||
pools[f"pool_{_i + 1}_url"] = _pool.url.replace(
|
|
||||||
"stratum+tcp://", ""
|
|
||||||
).replace("stratum2+tcp://", "")
|
|
||||||
pools[f"pool_{_i + 1}_user"] = _pool.username
|
|
||||||
groups.append(pools)
|
|
||||||
return groups
|
|
||||||
else:
|
|
||||||
groups[0][f"pool_{i + 1}_url"] = (
|
|
||||||
pool["URL"]
|
|
||||||
.replace("stratum+tcp://", "")
|
|
||||||
.replace("stratum2+tcp://", "")
|
|
||||||
)
|
|
||||||
groups[0][f"pool_{i + 1}_user"] = pool["User"]
|
|
||||||
else:
|
|
||||||
groups = []
|
|
||||||
cfg = await self.get_config()
|
|
||||||
if cfg:
|
|
||||||
for group in cfg.pool_groups:
|
|
||||||
pools = {"quota": group.quota}
|
|
||||||
for _i, _pool in enumerate(group.pools):
|
|
||||||
pools[f"pool_{_i + 1}_url"] = _pool.url.replace(
|
|
||||||
"stratum+tcp://", ""
|
|
||||||
).replace("stratum2+tcp://", "")
|
|
||||||
pools[f"pool_{_i + 1}_user"] = _pool.username
|
|
||||||
groups.append(pools)
|
|
||||||
return groups
|
|
||||||
return groups
|
|
||||||
|
|
||||||
async def get_errors(self) -> List[MinerErrorData]:
|
async def get_errors(self) -> List[MinerErrorData]:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -16,38 +16,61 @@
|
|||||||
|
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
from pyasic import MinerConfig
|
||||||
from pyasic.errors import APIError
|
from pyasic.errors import APIError
|
||||||
from pyasic.logger import logger
|
from pyasic.logger import logger
|
||||||
from pyasic.miners.backends.bmminer import BMMiner
|
from pyasic.miners.backends.bmminer import BMMiner
|
||||||
|
from pyasic.miners.base import (
|
||||||
|
DataFunction,
|
||||||
|
DataLocations,
|
||||||
|
DataOptions,
|
||||||
|
RPCAPICommand,
|
||||||
|
WebAPICommand,
|
||||||
|
)
|
||||||
from pyasic.web.vnish import VNishWebAPI
|
from pyasic.web.vnish import VNishWebAPI
|
||||||
|
|
||||||
VNISH_DATA_LOC = {
|
VNISH_DATA_LOC = DataLocations(
|
||||||
"mac": {"cmd": "get_mac", "kwargs": {"web_summary": {"web": "summary"}}},
|
**{
|
||||||
"model": {"cmd": "get_model", "kwargs": {}},
|
str(DataOptions.MAC): DataFunction(
|
||||||
"api_ver": {"cmd": "get_api_ver", "kwargs": {"api_version": {"api": "version"}}},
|
"get_mac", [WebAPICommand("web_summary", "summary")]
|
||||||
"fw_ver": {"cmd": "get_fw_ver", "kwargs": {"web_summary": {"web": "summary"}}},
|
),
|
||||||
"hostname": {"cmd": "get_hostname", "kwargs": {"web_summary": {"web": "summary"}}},
|
str(DataOptions.MODEL): DataFunction("get_model"),
|
||||||
"hashrate": {"cmd": "get_hashrate", "kwargs": {"api_summary": {"api": "summary"}}},
|
str(DataOptions.API_VERSION): DataFunction(
|
||||||
"expected_hashrate": {
|
"get_api_ver", [RPCAPICommand("api_version", "version")]
|
||||||
"cmd": "get_nominal_hashrate",
|
),
|
||||||
"kwargs": {"api_stats": {"api": "stats"}},
|
str(DataOptions.FW_VERSION): DataFunction(
|
||||||
},
|
"get_fw_ver", [WebAPICommand("web_summary", "summary")]
|
||||||
"hashboards": {"cmd": "get_hashboards", "kwargs": {"api_stats": {"api": "stats"}}},
|
),
|
||||||
"env_temp": {"cmd": "get_env_temp", "kwargs": {}},
|
str(DataOptions.HOSTNAME): DataFunction(
|
||||||
"wattage": {"cmd": "get_wattage", "kwargs": {"web_summary": {"web": "summary"}}},
|
"get_hostname", [WebAPICommand("web_summary", "summary")]
|
||||||
"wattage_limit": {
|
),
|
||||||
"cmd": "get_wattage_limit",
|
str(DataOptions.HASHRATE): DataFunction(
|
||||||
"kwargs": {"web_settings": {"web": "settings"}},
|
"get_hashrate", [RPCAPICommand("api_summary", "summary")]
|
||||||
},
|
),
|
||||||
"fans": {"cmd": "get_fans", "kwargs": {"api_stats": {"api": "stats"}}},
|
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
|
||||||
"fan_psu": {"cmd": "get_fan_psu", "kwargs": {}},
|
"get_expected_hashrate", [RPCAPICommand("api_stats", "stats")]
|
||||||
"errors": {"cmd": "get_errors", "kwargs": {}},
|
),
|
||||||
"fault_light": {"cmd": "get_fault_light", "kwargs": {}},
|
str(DataOptions.HASHBOARDS): DataFunction(
|
||||||
"pools": {"cmd": "get_pools", "kwargs": {"api_pools": {"api": "pools"}}},
|
"get_hashboards", [RPCAPICommand("api_stats", "stats")]
|
||||||
"is_mining": {"cmd": "is_mining", "kwargs": {}},
|
),
|
||||||
"uptime": {"cmd": "get_uptime", "kwargs": {}},
|
str(DataOptions.ENVIRONMENT_TEMP): DataFunction("get_env_temp"),
|
||||||
"config": {"cmd": "get_config", "kwargs": {}},
|
str(DataOptions.WATTAGE): DataFunction(
|
||||||
|
"get_wattage", [WebAPICommand("web_summary", "summary")]
|
||||||
|
),
|
||||||
|
str(DataOptions.WATTAGE_LIMIT): DataFunction(
|
||||||
|
"get_wattage_limit", [WebAPICommand("web_settings", "settings")]
|
||||||
|
),
|
||||||
|
str(DataOptions.FANS): DataFunction(
|
||||||
|
"get_fans", [RPCAPICommand("api_stats", "stats")]
|
||||||
|
),
|
||||||
|
str(DataOptions.FAN_PSU): DataFunction("get_fan_psu"),
|
||||||
|
str(DataOptions.ERRORS): DataFunction("get_errors"),
|
||||||
|
str(DataOptions.FAULT_LIGHT): DataFunction("get_fault_light"),
|
||||||
|
str(DataOptions.IS_MINING): DataFunction("is_mining"),
|
||||||
|
str(DataOptions.UPTIME): DataFunction("get_uptime"),
|
||||||
|
str(DataOptions.CONFIG): DataFunction("get_config"),
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class VNish(BMMiner):
|
class VNish(BMMiner):
|
||||||
@@ -197,3 +220,11 @@ class VNish(BMMiner):
|
|||||||
|
|
||||||
async def get_uptime(self, *args, **kwargs) -> Optional[int]:
|
async def get_uptime(self, *args, **kwargs) -> Optional[int]:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
async def get_config(self) -> MinerConfig:
|
||||||
|
try:
|
||||||
|
web_settings = await self.web.settings()
|
||||||
|
except APIError:
|
||||||
|
return self.config
|
||||||
|
self.config = MinerConfig.from_vnish(web_settings)
|
||||||
|
return self.config
|
||||||
|
|||||||
@@ -17,7 +17,9 @@ import asyncio
|
|||||||
import ipaddress
|
import ipaddress
|
||||||
import logging
|
import logging
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
from typing import List, Optional, Tuple, TypeVar
|
from dataclasses import dataclass, field, make_dataclass
|
||||||
|
from enum import Enum
|
||||||
|
from typing import List, Optional, Tuple, TypeVar, Union
|
||||||
|
|
||||||
import asyncssh
|
import asyncssh
|
||||||
|
|
||||||
@@ -27,6 +29,70 @@ from pyasic.data.error_codes import MinerErrorData
|
|||||||
from pyasic.logger import logger
|
from pyasic.logger import logger
|
||||||
|
|
||||||
|
|
||||||
|
class DataOptions(Enum):
|
||||||
|
MAC = "mac"
|
||||||
|
MODEL = "model"
|
||||||
|
API_VERSION = "api_ver"
|
||||||
|
FW_VERSION = "fw_ver"
|
||||||
|
HOSTNAME = "hostname"
|
||||||
|
HASHRATE = "hashrate"
|
||||||
|
EXPECTED_HASHRATE = "expected_hashrate"
|
||||||
|
HASHBOARDS = "hashboards"
|
||||||
|
ENVIRONMENT_TEMP = "env_temp"
|
||||||
|
WATTAGE = "wattage"
|
||||||
|
WATTAGE_LIMIT = "wattage_limit"
|
||||||
|
FANS = "fans"
|
||||||
|
FAN_PSU = "fan_psu"
|
||||||
|
ERRORS = "errors"
|
||||||
|
FAULT_LIGHT = "fault_light"
|
||||||
|
IS_MINING = "is_mining"
|
||||||
|
UPTIME = "uptime"
|
||||||
|
CONFIG = "config"
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.value
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class RPCAPICommand:
|
||||||
|
name: str
|
||||||
|
cmd: str
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class WebAPICommand:
|
||||||
|
name: str
|
||||||
|
cmd: str
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class GRPCCommand(WebAPICommand):
|
||||||
|
name: str
|
||||||
|
cmd: str
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class GraphQLCommand(WebAPICommand):
|
||||||
|
name: str
|
||||||
|
cmd: dict
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class DataFunction:
|
||||||
|
cmd: str
|
||||||
|
kwargs: list[
|
||||||
|
Union[RPCAPICommand, WebAPICommand, GRPCCommand, GraphQLCommand]
|
||||||
|
] = field(default_factory=list)
|
||||||
|
|
||||||
|
|
||||||
|
DataLocations = make_dataclass(
|
||||||
|
"DataLocations",
|
||||||
|
[(enum_value.value, str) for enum_value in DataOptions],
|
||||||
|
)
|
||||||
|
# add default value with
|
||||||
|
# [(enum_value.value, str, , DataFunction(enum_value.value)) for enum_value in DataOptions],
|
||||||
|
|
||||||
|
|
||||||
class BaseMiner(ABC):
|
class BaseMiner(ABC):
|
||||||
def __init__(self, ip: str, *args, **kwargs) -> None:
|
def __init__(self, ip: str, *args, **kwargs) -> None:
|
||||||
# interfaces
|
# interfaces
|
||||||
@@ -46,7 +112,7 @@ class BaseMiner(ABC):
|
|||||||
self.expected_chips = 0
|
self.expected_chips = 0
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
# data gathering locations
|
# data gathering locations
|
||||||
self.data_locations = None
|
self.data_locations: DataLocations = None
|
||||||
# autotuning/shutdown support
|
# autotuning/shutdown support
|
||||||
self.supports_autotuning = False
|
self.supports_autotuning = False
|
||||||
self.supports_shutdown = False
|
self.supports_shutdown = False
|
||||||
@@ -359,15 +425,6 @@ class BaseMiner(ABC):
|
|||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
async def get_pools(self, *args, **kwargs) -> List[dict]:
|
|
||||||
"""Get pool information from the miner.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Pool groups and quotas in a list of dicts.
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
async def get_errors(self, *args, **kwargs) -> List[MinerErrorData]:
|
async def get_errors(self, *args, **kwargs) -> List[MinerErrorData]:
|
||||||
"""Get a list of the errors the miner is experiencing.
|
"""Get a list of the errors the miner is experiencing.
|
||||||
@@ -414,28 +471,33 @@ class BaseMiner(ABC):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
async def _get_data(
|
async def _get_data(
|
||||||
self, allow_warning: bool, include: list = None, exclude: list = None
|
self,
|
||||||
|
allow_warning: bool,
|
||||||
|
include: List[Union[str, DataOptions]] = None,
|
||||||
|
exclude: List[Union[str, DataOptions]] = None,
|
||||||
) -> dict:
|
) -> dict:
|
||||||
if include is None:
|
if include is not None:
|
||||||
|
include = [str(i) for i in include]
|
||||||
|
else:
|
||||||
# everything
|
# everything
|
||||||
include = list(self.data_locations.keys())
|
include = [str(enum_value.value) for enum_value in DataOptions]
|
||||||
|
|
||||||
if exclude is not None:
|
if exclude is not None:
|
||||||
for item in exclude:
|
for item in exclude:
|
||||||
if item in include:
|
if str(item) in include:
|
||||||
include.remove(item)
|
include.remove(str(item))
|
||||||
|
|
||||||
api_multicommand = set()
|
api_multicommand = set()
|
||||||
web_multicommand = []
|
web_multicommand = []
|
||||||
for data_name in include:
|
for data_name in include:
|
||||||
try:
|
try:
|
||||||
fn_args = self.data_locations[data_name]["kwargs"]
|
fn_args = getattr(self.data_locations, data_name).kwargs
|
||||||
for arg_name in fn_args:
|
for arg in fn_args:
|
||||||
if fn_args[arg_name].get("api"):
|
if isinstance(arg, RPCAPICommand):
|
||||||
api_multicommand.add(fn_args[arg_name]["api"])
|
api_multicommand.add(arg.cmd)
|
||||||
if fn_args[arg_name].get("web"):
|
if isinstance(arg, WebAPICommand):
|
||||||
if not fn_args[arg_name]["web"] in web_multicommand:
|
if arg.cmd not in web_multicommand:
|
||||||
web_multicommand.append(fn_args[arg_name]["web"])
|
web_multicommand.append(arg.cmd)
|
||||||
except KeyError as e:
|
except KeyError as e:
|
||||||
logger.error(e, data_name)
|
logger.error(e, data_name)
|
||||||
continue
|
continue
|
||||||
@@ -465,37 +527,36 @@ class BaseMiner(ABC):
|
|||||||
|
|
||||||
for data_name in include:
|
for data_name in include:
|
||||||
try:
|
try:
|
||||||
fn_args = self.data_locations[data_name]["kwargs"]
|
fn_args = getattr(self.data_locations, data_name).kwargs
|
||||||
args_to_send = {k: None for k in fn_args}
|
args_to_send = {k.name: None for k in fn_args}
|
||||||
for arg_name in fn_args:
|
for arg in fn_args:
|
||||||
try:
|
try:
|
||||||
if fn_args[arg_name].get("api"):
|
if isinstance(arg, RPCAPICommand):
|
||||||
if api_command_data.get("multicommand"):
|
if api_command_data.get("multicommand"):
|
||||||
args_to_send[arg_name] = api_command_data[
|
args_to_send[arg.name] = api_command_data[arg.cmd][0]
|
||||||
fn_args[arg_name]["api"]
|
|
||||||
][0]
|
|
||||||
else:
|
else:
|
||||||
args_to_send[arg_name] = api_command_data
|
args_to_send[arg.name] = api_command_data
|
||||||
if fn_args[arg_name].get("web"):
|
if isinstance(arg, WebAPICommand):
|
||||||
if web_command_data is not None:
|
if web_command_data is not None:
|
||||||
if web_command_data.get("multicommand"):
|
if web_command_data.get("multicommand"):
|
||||||
args_to_send[arg_name] = web_command_data[
|
args_to_send[arg.name] = web_command_data[arg.cmd]
|
||||||
fn_args[arg_name]["web"]
|
|
||||||
]
|
|
||||||
else:
|
else:
|
||||||
if not web_command_data == {"multicommand": False}:
|
if not web_command_data == {"multicommand": False}:
|
||||||
args_to_send[arg_name] = web_command_data
|
args_to_send[arg.name] = web_command_data
|
||||||
except LookupError:
|
except LookupError:
|
||||||
args_to_send[arg_name] = None
|
args_to_send[arg.name] = None
|
||||||
except LookupError:
|
except LookupError:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
function = getattr(self, self.data_locations[data_name]["cmd"])
|
function = getattr(self, getattr(self.data_locations, data_name).cmd)
|
||||||
miner_data[data_name] = await function(**args_to_send)
|
miner_data[data_name] = await function(**args_to_send)
|
||||||
return miner_data
|
return miner_data
|
||||||
|
|
||||||
async def get_data(
|
async def get_data(
|
||||||
self, allow_warning: bool = False, include: list = None, exclude: list = None
|
self,
|
||||||
|
allow_warning: bool = False,
|
||||||
|
include: List[Union[str, DataOptions]] = None,
|
||||||
|
exclude: List[Union[str, DataOptions]] = None,
|
||||||
) -> MinerData:
|
) -> MinerData:
|
||||||
"""Get data from the miner in the form of [`MinerData`][pyasic.data.MinerData].
|
"""Get data from the miner in the form of [`MinerData`][pyasic.data.MinerData].
|
||||||
|
|
||||||
|
|||||||
@@ -267,32 +267,6 @@ class CGMinerA10X(CGMiner, A10X):
|
|||||||
|
|
||||||
return fans
|
return fans
|
||||||
|
|
||||||
async def get_pools(self, api_pools: dict = None) -> List[dict]:
|
|
||||||
groups = []
|
|
||||||
|
|
||||||
if not api_pools:
|
|
||||||
try:
|
|
||||||
api_pools = await self.api.pools()
|
|
||||||
except APIError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if api_pools:
|
|
||||||
try:
|
|
||||||
pools = {}
|
|
||||||
for i, pool in enumerate(api_pools["POOLS"]):
|
|
||||||
pools[f"pool_{i + 1}_url"] = (
|
|
||||||
pool["URL"]
|
|
||||||
.replace("stratum+tcp://", "")
|
|
||||||
.replace("stratum2+tcp://", "")
|
|
||||||
)
|
|
||||||
pools[f"pool_{i + 1}_user"] = pool["User"]
|
|
||||||
pools["quota"] = pool["Quota"] if pool.get("Quota") else "0"
|
|
||||||
|
|
||||||
groups.append(pools)
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
return groups
|
|
||||||
|
|
||||||
async def get_errors(
|
async def get_errors(
|
||||||
self, web_get_error_detail: dict = None
|
self, web_get_error_detail: dict = None
|
||||||
) -> List[MinerErrorData]: # noqa: named this way for automatic functionality
|
) -> List[MinerErrorData]: # noqa: named this way for automatic functionality
|
||||||
|
|||||||
@@ -246,32 +246,6 @@ class CGMinerT3HPlus(CGMiner, T3HPlus):
|
|||||||
|
|
||||||
return fans
|
return fans
|
||||||
|
|
||||||
async def get_pools(self, api_pools: dict = None) -> List[dict]:
|
|
||||||
groups = []
|
|
||||||
|
|
||||||
if not api_pools:
|
|
||||||
try:
|
|
||||||
api_pools = await self.api.pools()
|
|
||||||
except APIError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if api_pools:
|
|
||||||
try:
|
|
||||||
pools = {}
|
|
||||||
for i, pool in enumerate(api_pools["POOLS"]):
|
|
||||||
pools[f"pool_{i + 1}_url"] = (
|
|
||||||
pool["URL"]
|
|
||||||
.replace("stratum+tcp://", "")
|
|
||||||
.replace("stratum2+tcp://", "")
|
|
||||||
)
|
|
||||||
pools[f"pool_{i + 1}_user"] = pool["User"]
|
|
||||||
pools["quota"] = pool["Quota"] if pool.get("Quota") else "0"
|
|
||||||
|
|
||||||
groups.append(pools)
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
return groups
|
|
||||||
|
|
||||||
async def get_errors(
|
async def get_errors(
|
||||||
self, web_get_error_detail: dict = None
|
self, web_get_error_detail: dict = None
|
||||||
) -> List[MinerErrorData]: # noqa: named this way for automatic functionality
|
) -> List[MinerErrorData]: # noqa: named this way for automatic functionality
|
||||||
|
|||||||
@@ -92,6 +92,7 @@ MINER_CLASSES = {
|
|||||||
"ANTMINER S19 XP": BMMinerS19XP,
|
"ANTMINER S19 XP": BMMinerS19XP,
|
||||||
"ANTMINER S19A": BMMinerS19a,
|
"ANTMINER S19A": BMMinerS19a,
|
||||||
"ANTMINER S19A PRO": BMMinerS19aPro,
|
"ANTMINER S19A PRO": BMMinerS19aPro,
|
||||||
|
"ANTMINER S19 PRO HYD.": BMMinerS19ProHydro,
|
||||||
"ANTMINER T19": BMMinerT19,
|
"ANTMINER T19": BMMinerT19,
|
||||||
},
|
},
|
||||||
MinerTypes.WHATSMINER: {
|
MinerTypes.WHATSMINER: {
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ class S19NoPIC(AntMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "S19 No PIC"
|
self.model = "S19 No PIC"
|
||||||
self.nominal_chips = 88
|
self.expected_chips = 88
|
||||||
self.fan_count = 4
|
self.fan_count = 4
|
||||||
|
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ class S19i(AntMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "S19i"
|
self.model = "S19i"
|
||||||
self.nominal_chips = 80
|
self.expected_chips = 80
|
||||||
self.fan_count = 4
|
self.fan_count = 4
|
||||||
|
|
||||||
|
|
||||||
@@ -58,7 +58,7 @@ class S19Plus(AntMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "S19+"
|
self.model = "S19+"
|
||||||
self.nominal_chips = 80
|
self.expected_chips = 80
|
||||||
self.fan_count = 4
|
self.fan_count = 4
|
||||||
|
|
||||||
|
|
||||||
@@ -76,7 +76,7 @@ class S19XP(AntMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "S19 XP"
|
self.model = "S19 XP"
|
||||||
self.nominal_chips = 110
|
self.expected_chips = 110
|
||||||
self.fan_count = 4
|
self.fan_count = 4
|
||||||
|
|
||||||
|
|
||||||
@@ -94,7 +94,7 @@ class S19aPro(AntMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "S19a Pro"
|
self.model = "S19a Pro"
|
||||||
self.nominal_chips = 100
|
self.expected_chips = 100
|
||||||
self.fan_count = 4
|
self.fan_count = 4
|
||||||
|
|
||||||
|
|
||||||
@@ -103,7 +103,7 @@ class S19j(AntMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "S19j"
|
self.model = "S19j"
|
||||||
self.nominal_chips = 114
|
self.expected_chips = 114
|
||||||
self.fan_count = 4
|
self.fan_count = 4
|
||||||
|
|
||||||
|
|
||||||
@@ -112,7 +112,7 @@ class S19jNoPIC(AntMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "S19j No PIC"
|
self.model = "S19j No PIC"
|
||||||
self.nominal_chips = 88
|
self.expected_chips = 88
|
||||||
self.fan_count = 4
|
self.fan_count = 4
|
||||||
|
|
||||||
|
|
||||||
@@ -121,7 +121,7 @@ class S19jPro(AntMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "S19j Pro"
|
self.model = "S19j Pro"
|
||||||
self.nominal_chips = 126
|
self.expected_chips = 126
|
||||||
self.fan_count = 4
|
self.fan_count = 4
|
||||||
|
|
||||||
|
|
||||||
@@ -130,7 +130,7 @@ class S19jProPlus(AntMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "S19j Pro+"
|
self.model = "S19j Pro+"
|
||||||
self.nominal_chips = 120
|
self.expected_chips = 120
|
||||||
self.fan_count = 4
|
self.fan_count = 4
|
||||||
|
|
||||||
|
|
||||||
@@ -139,7 +139,7 @@ class S19kPro(AntMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "S19k Pro"
|
self.model = "S19k Pro"
|
||||||
self.nominal_chips = 77
|
self.expected_chips = 77
|
||||||
self.fan_count = 4
|
self.fan_count = 4
|
||||||
|
|
||||||
|
|
||||||
@@ -157,5 +157,15 @@ class S19kProNoPIC(AntMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "S19k Pro No PIC"
|
self.model = "S19k Pro No PIC"
|
||||||
self.nominal_chips = 77
|
self.expected_chips = 77
|
||||||
self.fan_count = 4
|
self.fan_count = 4
|
||||||
|
|
||||||
|
|
||||||
|
class S19ProHydro(AntMiner): # noqa - ignore ABC method implementation
|
||||||
|
def __init__(self, ip: str, api_ver: str = "0.0.0"):
|
||||||
|
super().__init__(ip, api_ver)
|
||||||
|
self.ip = ip
|
||||||
|
self.model = "S19 Pro Hydro"
|
||||||
|
self.expected_chips = 180
|
||||||
|
self.expected_hashboards = 4
|
||||||
|
self.fan_count = 0
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ from .S19 import (
|
|||||||
S19NoPIC,
|
S19NoPIC,
|
||||||
S19Plus,
|
S19Plus,
|
||||||
S19Pro,
|
S19Pro,
|
||||||
|
S19ProHydro,
|
||||||
S19ProPlus,
|
S19ProPlus,
|
||||||
)
|
)
|
||||||
from .T19 import T19
|
from .T19 import T19
|
||||||
|
|||||||
@@ -40,5 +40,5 @@ class S9j(AntMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "S9j"
|
self.model = "S9j"
|
||||||
self.nominal_chips = 63
|
self.expected_chips = 63
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ class M20SV20(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M20S V20"
|
self.model = "M20S V20"
|
||||||
self.nominal_chips = 111
|
self.expected_chips = 111
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -33,5 +33,5 @@ class M30V20(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30 V20"
|
self.model = "M30 V20"
|
||||||
self.nominal_chips = 111
|
self.expected_chips = 111
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ class M30SV20(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S V20"
|
self.model = "M30S V20"
|
||||||
self.nominal_chips = 156
|
self.expected_chips = 156
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ class M30SV30(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S V30"
|
self.model = "M30S V30"
|
||||||
self.nominal_chips = 164
|
self.expected_chips = 164
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -60,7 +60,7 @@ class M30SV50(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S V50"
|
self.model = "M30S V50"
|
||||||
self.nominal_chips = 156
|
self.expected_chips = 156
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -69,7 +69,7 @@ class M30SV60(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S V60"
|
self.model = "M30S V60"
|
||||||
self.nominal_chips = 164
|
self.expected_chips = 164
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -78,7 +78,7 @@ class M30SV70(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S V70"
|
self.model = "M30S V70"
|
||||||
self.nominal_chips = 0
|
self.expected_chips = 0
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
"Unknown chip count for miner type M30SV70, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
"Unknown chip count for miner type M30SV70, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
||||||
)
|
)
|
||||||
@@ -90,7 +90,7 @@ class M30SV80(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S V80"
|
self.model = "M30S V80"
|
||||||
self.nominal_chips = 129
|
self.expected_chips = 129
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -108,7 +108,7 @@ class M30SVE20(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S VE20"
|
self.model = "M30S VE20"
|
||||||
self.nominal_chips = 111
|
self.expected_chips = 111
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -117,7 +117,7 @@ class M30SVE30(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S VE30"
|
self.model = "M30S VE30"
|
||||||
self.nominal_chips = 117
|
self.expected_chips = 117
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -126,7 +126,7 @@ class M30SVE40(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S VE40"
|
self.model = "M30S VE40"
|
||||||
self.nominal_chips = 123
|
self.expected_chips = 123
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -135,7 +135,7 @@ class M30SVE50(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S VE50"
|
self.model = "M30S VE50"
|
||||||
self.nominal_chips = 129
|
self.expected_chips = 129
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -144,7 +144,7 @@ class M30SVE60(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S VE60"
|
self.model = "M30S VE60"
|
||||||
self.nominal_chips = 0
|
self.expected_chips = 0
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
"Unknown chip count for miner type M30SVE60, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
"Unknown chip count for miner type M30SVE60, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
||||||
)
|
)
|
||||||
@@ -156,7 +156,7 @@ class M30SVE70(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S VE70"
|
self.model = "M30S VE70"
|
||||||
self.nominal_chips = 0
|
self.expected_chips = 0
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
"Unknown chip count for miner type M30SVE70, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
"Unknown chip count for miner type M30SVE70, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
||||||
)
|
)
|
||||||
@@ -168,7 +168,7 @@ class M30SVF10(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S VF10"
|
self.model = "M30S VF10"
|
||||||
self.nominal_chips = 70
|
self.expected_chips = 70
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -186,7 +186,7 @@ class M30SVF30(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S VF30"
|
self.model = "M30S VF30"
|
||||||
self.nominal_chips = 78
|
self.expected_chips = 78
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -195,7 +195,7 @@ class M30SVG10(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S VG10"
|
self.model = "M30S VG10"
|
||||||
self.nominal_chips = 66
|
self.expected_chips = 66
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -213,7 +213,7 @@ class M30SVG30(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S VG30"
|
self.model = "M30S VG30"
|
||||||
self.nominal_chips = 74
|
self.expected_chips = 74
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -222,7 +222,7 @@ class M30SVG40(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S VG40"
|
self.model = "M30S VG40"
|
||||||
self.nominal_chips = 78
|
self.expected_chips = 78
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -240,7 +240,7 @@ class M30SVH20(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S VH20"
|
self.model = "M30S VH20"
|
||||||
self.nominal_chips = 66
|
self.expected_chips = 66
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -249,7 +249,7 @@ class M30SVH30(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S VH30"
|
self.model = "M30S VH30"
|
||||||
self.nominal_chips = 0
|
self.expected_chips = 0
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
"Unknown chip count for miner type M30SVH30, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
"Unknown chip count for miner type M30SVH30, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
||||||
)
|
)
|
||||||
@@ -261,7 +261,7 @@ class M30SVH40(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S VH40"
|
self.model = "M30S VH40"
|
||||||
self.nominal_chips = 64
|
self.expected_chips = 64
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -270,7 +270,7 @@ class M30SVH50(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S VH50"
|
self.model = "M30S VH50"
|
||||||
self.nominal_chips = 66
|
self.expected_chips = 66
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -291,5 +291,5 @@ class M30SVI20(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S VI20"
|
self.model = "M30S VI20"
|
||||||
self.nominal_chips = 70
|
self.expected_chips = 70
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ class M30SPlusV30(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S+ V30"
|
self.model = "M30S+ V30"
|
||||||
self.nominal_chips = 0
|
self.expected_chips = 0
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
"Unknown chip count for miner type M30S+ V30, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
"Unknown chip count for miner type M30S+ V30, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
||||||
)
|
)
|
||||||
@@ -54,7 +54,7 @@ class M30SPlusV40(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S+ V40"
|
self.model = "M30S+ V40"
|
||||||
self.nominal_chips = 235
|
self.expected_chips = 235
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -63,7 +63,7 @@ class M30SPlusV50(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S+ V50"
|
self.model = "M30S+ V50"
|
||||||
self.nominal_chips = 225
|
self.expected_chips = 225
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -72,7 +72,7 @@ class M30SPlusV60(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S+ V60"
|
self.model = "M30S+ V60"
|
||||||
self.nominal_chips = 245
|
self.expected_chips = 245
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -81,7 +81,7 @@ class M30SPlusV70(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S+ V70"
|
self.model = "M30S+ V70"
|
||||||
self.nominal_chips = 235
|
self.expected_chips = 235
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -99,7 +99,7 @@ class M30SPlusV90(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S+ V90"
|
self.model = "M30S+ V90"
|
||||||
self.nominal_chips = 225
|
self.expected_chips = 225
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -108,7 +108,7 @@ class M30SPlusV100(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S+ V100"
|
self.model = "M30S+ V100"
|
||||||
self.nominal_chips = 215
|
self.expected_chips = 215
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -126,7 +126,7 @@ class M30SPlusVE40(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S+ VE40"
|
self.model = "M30S+ VE40"
|
||||||
self.nominal_chips = 156
|
self.expected_chips = 156
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -135,7 +135,7 @@ class M30SPlusVE50(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S+ VE50"
|
self.model = "M30S+ VE50"
|
||||||
self.nominal_chips = 164
|
self.expected_chips = 164
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -153,7 +153,7 @@ class M30SPlusVE70(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S+ VE70"
|
self.model = "M30S+ VE70"
|
||||||
self.nominal_chips = 0
|
self.expected_chips = 0
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
"Unknown chip count for miner type M30S+ VE70, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
"Unknown chip count for miner type M30S+ VE70, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
||||||
)
|
)
|
||||||
@@ -165,7 +165,7 @@ class M30SPlusVE80(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S+ VE80"
|
self.model = "M30S+ VE80"
|
||||||
self.nominal_chips = 0
|
self.expected_chips = 0
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
"Unknown chip count for miner type M30S+ VE80, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
"Unknown chip count for miner type M30S+ VE80, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
||||||
)
|
)
|
||||||
@@ -177,7 +177,7 @@ class M30SPlusVE90(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S+ VE90"
|
self.model = "M30S+ VE90"
|
||||||
self.nominal_chips = 0
|
self.expected_chips = 0
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
"Unknown chip count for miner type M30S+ VE90, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
"Unknown chip count for miner type M30S+ VE90, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
||||||
)
|
)
|
||||||
@@ -189,7 +189,7 @@ class M30SPlusVE100(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S+ VE100"
|
self.model = "M30S+ VE100"
|
||||||
self.nominal_chips = 0
|
self.expected_chips = 0
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
"Unknown chip count for miner type M30S+ VE100, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
"Unknown chip count for miner type M30S+ VE100, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
||||||
)
|
)
|
||||||
@@ -201,7 +201,7 @@ class M30SPlusVF20(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S+ VF20"
|
self.model = "M30S+ VF20"
|
||||||
self.nominal_chips = 111
|
self.expected_chips = 111
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -219,7 +219,7 @@ class M30SPlusVG20(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S+ VG20"
|
self.model = "M30S+ VG20"
|
||||||
self.nominal_chips = 82
|
self.expected_chips = 82
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -228,7 +228,7 @@ class M30SPlusVG30(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S+ VG30"
|
self.model = "M30S+ VG30"
|
||||||
self.nominal_chips = 78
|
self.expected_chips = 78
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -246,7 +246,7 @@ class M30SPlusVG50(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S+ VG50"
|
self.model = "M30S+ VG50"
|
||||||
self.nominal_chips = 111
|
self.expected_chips = 111
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -255,7 +255,7 @@ class M30SPlusVG60(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S+ VG60"
|
self.model = "M30S+ VG60"
|
||||||
self.nominal_chips = 86
|
self.expected_chips = 86
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -273,7 +273,7 @@ class M30SPlusVH20(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S+ VH20"
|
self.model = "M30S+ VH20"
|
||||||
self.nominal_chips = 66
|
self.expected_chips = 66
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -282,7 +282,7 @@ class M30SPlusVH30(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S+ VH30"
|
self.model = "M30S+ VH30"
|
||||||
self.nominal_chips = 70
|
self.expected_chips = 70
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -291,7 +291,7 @@ class M30SPlusVH40(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S+ VH40"
|
self.model = "M30S+ VH40"
|
||||||
self.nominal_chips = 74
|
self.expected_chips = 74
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -300,7 +300,7 @@ class M30SPlusVH50(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S+ VH50"
|
self.model = "M30S+ VH50"
|
||||||
self.nominal_chips = 64
|
self.expected_chips = 64
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ class M30SPlusPlusVE30(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S++ VE30"
|
self.model = "M30S++ VE30"
|
||||||
self.nominal_chips = 215
|
self.expected_chips = 215
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -53,7 +53,7 @@ class M30SPlusPlusVE40(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S++ VE40"
|
self.model = "M30S++ VE40"
|
||||||
self.nominal_chips = 225
|
self.expected_chips = 225
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -71,7 +71,7 @@ class M30SPlusPlusVF40(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S++ VF40"
|
self.model = "M30S++ VF40"
|
||||||
self.nominal_chips = 156
|
self.expected_chips = 156
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -80,7 +80,7 @@ class M30SPlusPlusVG30(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S++ VG30"
|
self.model = "M30S++ VG30"
|
||||||
self.nominal_chips = 111
|
self.expected_chips = 111
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -89,7 +89,7 @@ class M30SPlusPlusVG40(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S++ VG40"
|
self.model = "M30S++ VG40"
|
||||||
self.nominal_chips = 117
|
self.expected_chips = 117
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -98,7 +98,7 @@ class M30SPlusPlusVG50(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S++ VG50"
|
self.model = "M30S++ VG50"
|
||||||
self.nominal_chips = 0
|
self.expected_chips = 0
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
"Unknown chip count for miner type M30S++ VG50, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
"Unknown chip count for miner type M30S++ VG50, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
||||||
)
|
)
|
||||||
@@ -110,7 +110,7 @@ class M30SPlusPlusVH10(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S++ VH10"
|
self.model = "M30S++ VH10"
|
||||||
self.nominal_chips = 82
|
self.expected_chips = 82
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -128,7 +128,7 @@ class M30SPlusPlusVH30(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S++ VH30"
|
self.model = "M30S++ VH30"
|
||||||
self.nominal_chips = 111
|
self.expected_chips = 111
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -137,7 +137,7 @@ class M30SPlusPlusVH40(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S++ VH40"
|
self.model = "M30S++ VH40"
|
||||||
self.nominal_chips = 70
|
self.expected_chips = 70
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -146,7 +146,7 @@ class M30SPlusPlusVH50(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S++ VH50"
|
self.model = "M30S++ VH50"
|
||||||
self.nominal_chips = 74
|
self.expected_chips = 74
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -155,7 +155,7 @@ class M30SPlusPlusVH60(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S++ VH60"
|
self.model = "M30S++ VH60"
|
||||||
self.nominal_chips = 78
|
self.expected_chips = 78
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -173,7 +173,7 @@ class M30SPlusPlusVH80(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S++ VH80"
|
self.model = "M30S++ VH80"
|
||||||
self.nominal_chips = 74
|
self.expected_chips = 74
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -182,7 +182,7 @@ class M30SPlusPlusVH90(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S++ VH90"
|
self.model = "M30S++ VH90"
|
||||||
self.nominal_chips = 78
|
self.expected_chips = 78
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -200,7 +200,7 @@ class M30SPlusPlusVJ20(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S++ VJ20"
|
self.model = "M30S++ VJ20"
|
||||||
self.nominal_chips = 0
|
self.expected_chips = 0
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
"Unknown chip count for miner type M30S++ VJ20, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
"Unknown chip count for miner type M30S++ VJ20, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
||||||
)
|
)
|
||||||
@@ -212,7 +212,7 @@ class M30SPlusPlusVJ30(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M30S++ VJ30"
|
self.model = "M30S++ VJ30"
|
||||||
self.nominal_chips = 0
|
self.expected_chips = 0
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
"Unknown chip count for miner type M30S++ VJ30, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
"Unknown chip count for miner type M30S++ VJ30, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -33,5 +33,5 @@ class M31V20(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M31 V20"
|
self.model = "M31 V20"
|
||||||
self.nominal_chips = 74
|
self.expected_chips = 74
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ class M31SPlusV40(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M31S+ V40"
|
self.model = "M31S+ V40"
|
||||||
self.nominal_chips = 123
|
self.expected_chips = 123
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -60,7 +60,7 @@ class M31SPlusV50(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M31S+ V50"
|
self.model = "M31S+ V50"
|
||||||
self.nominal_chips = 148
|
self.expected_chips = 148
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -69,7 +69,7 @@ class M31SPlusV60(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M31S+ V60"
|
self.model = "M31S+ V60"
|
||||||
self.nominal_chips = 156
|
self.expected_chips = 156
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -78,7 +78,7 @@ class M31SPlusV80(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M31S+ V80"
|
self.model = "M31S+ V80"
|
||||||
self.nominal_chips = 129
|
self.expected_chips = 129
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -87,7 +87,7 @@ class M31SPlusV90(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M31S+ V90"
|
self.model = "M31S+ V90"
|
||||||
self.nominal_chips = 117
|
self.expected_chips = 117
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -96,7 +96,7 @@ class M31SPlusV100(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M31S+ V100"
|
self.model = "M31S+ V100"
|
||||||
self.nominal_chips = 111
|
self.expected_chips = 111
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -105,7 +105,7 @@ class M31SPlusVE10(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M31S+ VE10"
|
self.model = "M31S+ VE10"
|
||||||
self.nominal_chips = 82
|
self.expected_chips = 82
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -114,7 +114,7 @@ class M31SPlusVE20(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M31S+ VE20"
|
self.model = "M31S+ VE20"
|
||||||
self.nominal_chips = 78
|
self.expected_chips = 78
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ class M50VH30(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M50 VH30"
|
self.model = "M50 VH30"
|
||||||
self.nominal_chips = 117
|
self.expected_chips = 117
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -70,7 +70,7 @@ class M50VH40(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M50 VH40"
|
self.model = "M50 VH40"
|
||||||
self.nominal_chips = 84
|
self.expected_chips = 84
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -79,7 +79,7 @@ class M50VH50(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M50 VH50"
|
self.model = "M50 VH50"
|
||||||
self.nominal_chips = 105
|
self.expected_chips = 105
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -88,7 +88,7 @@ class M50VH60(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M50 VH60"
|
self.model = "M50 VH60"
|
||||||
self.nominal_chips = 84
|
self.expected_chips = 84
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -97,7 +97,7 @@ class M50VH70(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M50 VH70"
|
self.model = "M50 VH70"
|
||||||
self.nominal_chips = 0
|
self.expected_chips = 0
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
"Unknown chip count for miner type M50 VH70, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
"Unknown chip count for miner type M50 VH70, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
||||||
)
|
)
|
||||||
@@ -109,7 +109,7 @@ class M50VH80(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M50 VH80"
|
self.model = "M50 VH80"
|
||||||
self.nominal_chips = 111
|
self.expected_chips = 111
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
|
|
||||||
|
|
||||||
@@ -118,7 +118,7 @@ class M50VJ10(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M50 VJ10"
|
self.model = "M50 VJ10"
|
||||||
self.nominal_chips = 0
|
self.expected_chips = 0
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
"Unknown chip count for miner type M50 VJ10, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
"Unknown chip count for miner type M50 VJ10, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
||||||
)
|
)
|
||||||
@@ -130,7 +130,7 @@ class M50VJ20(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M50 VJ20"
|
self.model = "M50 VJ20"
|
||||||
self.nominal_chips = 0
|
self.expected_chips = 0
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
"Unknown chip count for miner type M50 VJ20, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
"Unknown chip count for miner type M50 VJ20, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ class M60VK40(WhatsMiner): # noqa - ignore ABC method implementation
|
|||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.model = "M60 VK40"
|
self.model = "M60 VK40"
|
||||||
self.nominal_chips = 0
|
self.expected_chips = 0
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
"Unknown chip count for miner type M60 VK40, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
"Unknown chip count for miner type M60 VK40, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -113,32 +113,6 @@ class UnknownMiner(BaseMiner):
|
|||||||
async def get_fw_ver(self) -> Optional[str]:
|
async def get_fw_ver(self) -> Optional[str]:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
async def get_pools(self, api_pools: dict = None) -> List[dict]:
|
|
||||||
groups = []
|
|
||||||
|
|
||||||
if not api_pools:
|
|
||||||
try:
|
|
||||||
api_pools = await self.api.pools()
|
|
||||||
except APIError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if api_pools:
|
|
||||||
try:
|
|
||||||
pools = {}
|
|
||||||
for i, pool in enumerate(api_pools["POOLS"]):
|
|
||||||
pools[f"pool_{i + 1}_url"] = (
|
|
||||||
pool["URL"]
|
|
||||||
.replace("stratum+tcp://", "")
|
|
||||||
.replace("stratum2+tcp://", "")
|
|
||||||
)
|
|
||||||
pools[f"pool_{i + 1}_user"] = pool["User"]
|
|
||||||
pools["quota"] = pool["Quota"] if pool.get("Quota") else "0"
|
|
||||||
|
|
||||||
groups.append(pools)
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
return groups
|
|
||||||
|
|
||||||
async def get_errors(self) -> List[MinerErrorData]:
|
async def get_errors(self) -> List[MinerErrorData]:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
@@ -155,6 +129,6 @@ class UnknownMiner(BaseMiner):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
async def get_data(
|
async def get_data(
|
||||||
self, allow_warning: bool = False, data_to_get: list = None
|
self, allow_warning: bool = False, data_to_get: list = None, **kwargs
|
||||||
) -> MinerData:
|
) -> MinerData:
|
||||||
return MinerData(ip=str(self.ip))
|
return MinerData(ip=str(self.ip))
|
||||||
|
|||||||
@@ -123,9 +123,8 @@ class MinerNetwork:
|
|||||||
# clear cached miners
|
# clear cached miners
|
||||||
miner_factory.clear_cached_miners()
|
miner_factory.clear_cached_miners()
|
||||||
|
|
||||||
limit = asyncio.Semaphore(settings.get("network_scan_threads", 300))
|
|
||||||
miners = await asyncio.gather(
|
miners = await asyncio.gather(
|
||||||
*[self.ping_and_get_miner(host, limit) for host in self.hosts]
|
*[self.ping_and_get_miner(host) for host in self.hosts]
|
||||||
)
|
)
|
||||||
|
|
||||||
# remove all None from the miner list
|
# remove all None from the miner list
|
||||||
@@ -148,12 +147,8 @@ class MinerNetwork:
|
|||||||
loop = asyncio.get_event_loop()
|
loop = asyncio.get_event_loop()
|
||||||
|
|
||||||
# create a list of scan tasks
|
# create a list of scan tasks
|
||||||
limit = asyncio.Semaphore(settings.get("network_scan_threads", 300))
|
|
||||||
miners = asyncio.as_completed(
|
miners = asyncio.as_completed(
|
||||||
[
|
[loop.create_task(self.ping_and_get_miner(host)) for host in self.hosts]
|
||||||
loop.create_task(self.ping_and_get_miner(host, limit))
|
|
||||||
for host in self.hosts
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
for miner in miners:
|
for miner in miners:
|
||||||
try:
|
try:
|
||||||
@@ -162,16 +157,11 @@ class MinerNetwork:
|
|||||||
yield None
|
yield None
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def ping_and_get_miner(
|
async def ping_and_get_miner(ip: ipaddress.ip_address) -> Union[None, AnyMiner]:
|
||||||
ip: ipaddress.ip_address, semaphore: asyncio.Semaphore
|
|
||||||
) -> Union[None, AnyMiner]:
|
|
||||||
async with semaphore:
|
|
||||||
try:
|
try:
|
||||||
return await ping_and_get_miner(ip)
|
return await ping_and_get_miner(ip)
|
||||||
except ConnectionRefusedError:
|
except ConnectionRefusedError:
|
||||||
tasks = [
|
tasks = [ping_and_get_miner(ip, port=port) for port in [4028, 4029, 8889]]
|
||||||
ping_and_get_miner(ip, port=port) for port in [4028, 4029, 8889]
|
|
||||||
]
|
|
||||||
for miner in asyncio.as_completed(tasks):
|
for miner in asyncio.as_completed(tasks):
|
||||||
try:
|
try:
|
||||||
return await miner
|
return await miner
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ from httpx import AsyncHTTPTransport
|
|||||||
_settings = { # defaults
|
_settings = { # defaults
|
||||||
"network_ping_retries": 1,
|
"network_ping_retries": 1,
|
||||||
"network_ping_timeout": 3,
|
"network_ping_timeout": 3,
|
||||||
"network_scan_threads": 300,
|
|
||||||
"factory_get_retries": 1,
|
"factory_get_retries": 1,
|
||||||
"factory_get_timeout": 3,
|
"factory_get_timeout": 3,
|
||||||
"get_data_retries": 1,
|
"get_data_retries": 1,
|
||||||
|
|||||||
@@ -156,6 +156,8 @@ class BOSMinerGQLAPI:
|
|||||||
) -> dict:
|
) -> dict:
|
||||||
url = f"http://{self.ip}/graphql"
|
url = f"http://{self.ip}/graphql"
|
||||||
query = command
|
query = command
|
||||||
|
if command is None:
|
||||||
|
return {}
|
||||||
if command.get("query") is None:
|
if command.get("query") is None:
|
||||||
query = {"query": self.parse_command(command)}
|
query = {"query": self.parse_command(command)}
|
||||||
try:
|
try:
|
||||||
@@ -189,11 +191,13 @@ class BOSMinerGQLAPI:
|
|||||||
await client.post(
|
await client.post(
|
||||||
url,
|
url,
|
||||||
json={
|
json={
|
||||||
"query": 'mutation{auth{login(username:"'
|
"query": (
|
||||||
|
'mutation{auth{login(username:"'
|
||||||
+ "root"
|
+ "root"
|
||||||
+ '", password:"'
|
+ '", password:"'
|
||||||
+ self.pwd
|
+ self.pwd
|
||||||
+ '"){__typename}}}'
|
+ '"){__typename}}}'
|
||||||
|
)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -233,7 +237,9 @@ class BOSMinerLuCIAPI:
|
|||||||
login = {"luci_username": self.username, "luci_password": self.pwd}
|
login = {"luci_username": self.username, "luci_password": self.pwd}
|
||||||
url = f"http://{self.ip}/cgi-bin/luci"
|
url = f"http://{self.ip}/cgi-bin/luci"
|
||||||
headers = {
|
headers = {
|
||||||
"User-Agent": "BTC Tools v0.1", # only seems to respond if this user-agent is set
|
"User-Agent": (
|
||||||
|
"BTC Tools v0.1"
|
||||||
|
), # only seems to respond if this user-agent is set
|
||||||
"Content-Type": "application/x-www-form-urlencoded",
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
}
|
}
|
||||||
await session.post(url, headers=headers, data=login)
|
await session.post(url, headers=headers, data=login)
|
||||||
|
|||||||
@@ -2357,17 +2357,21 @@ class ActionsServiceBase(ServiceBase):
|
|||||||
RebootRequest,
|
RebootRequest,
|
||||||
RebootResponse,
|
RebootResponse,
|
||||||
),
|
),
|
||||||
"/braiins.bos.v1.ActionsService/SetLocateDeviceStatus": grpclib.const.Handler(
|
"/braiins.bos.v1.ActionsService/SetLocateDeviceStatus": (
|
||||||
|
grpclib.const.Handler(
|
||||||
self.__rpc_set_locate_device_status,
|
self.__rpc_set_locate_device_status,
|
||||||
grpclib.const.Cardinality.UNARY_UNARY,
|
grpclib.const.Cardinality.UNARY_UNARY,
|
||||||
SetLocateDeviceStatusRequest,
|
SetLocateDeviceStatusRequest,
|
||||||
LocateDeviceStatusResponse,
|
LocateDeviceStatusResponse,
|
||||||
|
)
|
||||||
),
|
),
|
||||||
"/braiins.bos.v1.ActionsService/GetLocateDeviceStatus": grpclib.const.Handler(
|
"/braiins.bos.v1.ActionsService/GetLocateDeviceStatus": (
|
||||||
|
grpclib.const.Handler(
|
||||||
self.__rpc_get_locate_device_status,
|
self.__rpc_get_locate_device_status,
|
||||||
grpclib.const.Cardinality.UNARY_UNARY,
|
grpclib.const.Cardinality.UNARY_UNARY,
|
||||||
GetLocateDeviceStatusRequest,
|
GetLocateDeviceStatusRequest,
|
||||||
LocateDeviceStatusResponse,
|
LocateDeviceStatusResponse,
|
||||||
|
)
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2644,17 +2648,21 @@ class PerformanceServiceBase(ServiceBase):
|
|||||||
GetTunerStateRequest,
|
GetTunerStateRequest,
|
||||||
GetTunerStateResponse,
|
GetTunerStateResponse,
|
||||||
),
|
),
|
||||||
"/braiins.bos.v1.PerformanceService/ListTargetProfiles": grpclib.const.Handler(
|
"/braiins.bos.v1.PerformanceService/ListTargetProfiles": (
|
||||||
|
grpclib.const.Handler(
|
||||||
self.__rpc_list_target_profiles,
|
self.__rpc_list_target_profiles,
|
||||||
grpclib.const.Cardinality.UNARY_UNARY,
|
grpclib.const.Cardinality.UNARY_UNARY,
|
||||||
ListTargetProfilesRequest,
|
ListTargetProfilesRequest,
|
||||||
ListTargetProfilesResponse,
|
ListTargetProfilesResponse,
|
||||||
|
)
|
||||||
),
|
),
|
||||||
"/braiins.bos.v1.PerformanceService/SetDefaultPowerTarget": grpclib.const.Handler(
|
"/braiins.bos.v1.PerformanceService/SetDefaultPowerTarget": (
|
||||||
|
grpclib.const.Handler(
|
||||||
self.__rpc_set_default_power_target,
|
self.__rpc_set_default_power_target,
|
||||||
grpclib.const.Cardinality.UNARY_UNARY,
|
grpclib.const.Cardinality.UNARY_UNARY,
|
||||||
SetDefaultPowerTargetRequest,
|
SetDefaultPowerTargetRequest,
|
||||||
SetPowerTargetResponse,
|
SetPowerTargetResponse,
|
||||||
|
)
|
||||||
),
|
),
|
||||||
"/braiins.bos.v1.PerformanceService/SetPowerTarget": grpclib.const.Handler(
|
"/braiins.bos.v1.PerformanceService/SetPowerTarget": grpclib.const.Handler(
|
||||||
self.__rpc_set_power_target,
|
self.__rpc_set_power_target,
|
||||||
@@ -2662,41 +2670,53 @@ class PerformanceServiceBase(ServiceBase):
|
|||||||
SetPowerTargetRequest,
|
SetPowerTargetRequest,
|
||||||
SetPowerTargetResponse,
|
SetPowerTargetResponse,
|
||||||
),
|
),
|
||||||
"/braiins.bos.v1.PerformanceService/IncrementPowerTarget": grpclib.const.Handler(
|
"/braiins.bos.v1.PerformanceService/IncrementPowerTarget": (
|
||||||
|
grpclib.const.Handler(
|
||||||
self.__rpc_increment_power_target,
|
self.__rpc_increment_power_target,
|
||||||
grpclib.const.Cardinality.UNARY_UNARY,
|
grpclib.const.Cardinality.UNARY_UNARY,
|
||||||
IncrementPowerTargetRequest,
|
IncrementPowerTargetRequest,
|
||||||
SetPowerTargetResponse,
|
SetPowerTargetResponse,
|
||||||
|
)
|
||||||
),
|
),
|
||||||
"/braiins.bos.v1.PerformanceService/DecrementPowerTarget": grpclib.const.Handler(
|
"/braiins.bos.v1.PerformanceService/DecrementPowerTarget": (
|
||||||
|
grpclib.const.Handler(
|
||||||
self.__rpc_decrement_power_target,
|
self.__rpc_decrement_power_target,
|
||||||
grpclib.const.Cardinality.UNARY_UNARY,
|
grpclib.const.Cardinality.UNARY_UNARY,
|
||||||
DecrementPowerTargetRequest,
|
DecrementPowerTargetRequest,
|
||||||
SetPowerTargetResponse,
|
SetPowerTargetResponse,
|
||||||
|
)
|
||||||
),
|
),
|
||||||
"/braiins.bos.v1.PerformanceService/SetDefaultHashrateTarget": grpclib.const.Handler(
|
"/braiins.bos.v1.PerformanceService/SetDefaultHashrateTarget": (
|
||||||
|
grpclib.const.Handler(
|
||||||
self.__rpc_set_default_hashrate_target,
|
self.__rpc_set_default_hashrate_target,
|
||||||
grpclib.const.Cardinality.UNARY_UNARY,
|
grpclib.const.Cardinality.UNARY_UNARY,
|
||||||
SetDefaultHashrateTargetRequest,
|
SetDefaultHashrateTargetRequest,
|
||||||
SetHashrateTargetResponse,
|
SetHashrateTargetResponse,
|
||||||
|
)
|
||||||
),
|
),
|
||||||
"/braiins.bos.v1.PerformanceService/SetHashrateTarget": grpclib.const.Handler(
|
"/braiins.bos.v1.PerformanceService/SetHashrateTarget": (
|
||||||
|
grpclib.const.Handler(
|
||||||
self.__rpc_set_hashrate_target,
|
self.__rpc_set_hashrate_target,
|
||||||
grpclib.const.Cardinality.UNARY_UNARY,
|
grpclib.const.Cardinality.UNARY_UNARY,
|
||||||
SetHashrateTargetRequest,
|
SetHashrateTargetRequest,
|
||||||
SetHashrateTargetResponse,
|
SetHashrateTargetResponse,
|
||||||
|
)
|
||||||
),
|
),
|
||||||
"/braiins.bos.v1.PerformanceService/IncrementHashrateTarget": grpclib.const.Handler(
|
"/braiins.bos.v1.PerformanceService/IncrementHashrateTarget": (
|
||||||
|
grpclib.const.Handler(
|
||||||
self.__rpc_increment_hashrate_target,
|
self.__rpc_increment_hashrate_target,
|
||||||
grpclib.const.Cardinality.UNARY_UNARY,
|
grpclib.const.Cardinality.UNARY_UNARY,
|
||||||
IncrementHashrateTargetRequest,
|
IncrementHashrateTargetRequest,
|
||||||
SetHashrateTargetResponse,
|
SetHashrateTargetResponse,
|
||||||
|
)
|
||||||
),
|
),
|
||||||
"/braiins.bos.v1.PerformanceService/DecrementHashrateTarget": grpclib.const.Handler(
|
"/braiins.bos.v1.PerformanceService/DecrementHashrateTarget": (
|
||||||
|
grpclib.const.Handler(
|
||||||
self.__rpc_decrement_hashrate_target,
|
self.__rpc_decrement_hashrate_target,
|
||||||
grpclib.const.Cardinality.UNARY_UNARY,
|
grpclib.const.Cardinality.UNARY_UNARY,
|
||||||
DecrementHashrateTargetRequest,
|
DecrementHashrateTargetRequest,
|
||||||
SetHashrateTargetResponse,
|
SetHashrateTargetResponse,
|
||||||
|
)
|
||||||
),
|
),
|
||||||
"/braiins.bos.v1.PerformanceService/SetDPS": grpclib.const.Handler(
|
"/braiins.bos.v1.PerformanceService/SetDPS": grpclib.const.Handler(
|
||||||
self.__rpc_set_dps,
|
self.__rpc_set_dps,
|
||||||
@@ -2704,23 +2724,29 @@ class PerformanceServiceBase(ServiceBase):
|
|||||||
SetDpsRequest,
|
SetDpsRequest,
|
||||||
SetDpsResponse,
|
SetDpsResponse,
|
||||||
),
|
),
|
||||||
"/braiins.bos.v1.PerformanceService/SetPerformanceMode": grpclib.const.Handler(
|
"/braiins.bos.v1.PerformanceService/SetPerformanceMode": (
|
||||||
|
grpclib.const.Handler(
|
||||||
self.__rpc_set_performance_mode,
|
self.__rpc_set_performance_mode,
|
||||||
grpclib.const.Cardinality.UNARY_UNARY,
|
grpclib.const.Cardinality.UNARY_UNARY,
|
||||||
SetPerformanceModeRequest,
|
SetPerformanceModeRequest,
|
||||||
PerformanceMode,
|
PerformanceMode,
|
||||||
|
)
|
||||||
),
|
),
|
||||||
"/braiins.bos.v1.PerformanceService/GetActivePerformanceMode": grpclib.const.Handler(
|
"/braiins.bos.v1.PerformanceService/GetActivePerformanceMode": (
|
||||||
|
grpclib.const.Handler(
|
||||||
self.__rpc_get_active_performance_mode,
|
self.__rpc_get_active_performance_mode,
|
||||||
grpclib.const.Cardinality.UNARY_UNARY,
|
grpclib.const.Cardinality.UNARY_UNARY,
|
||||||
GetPerformanceModeRequest,
|
GetPerformanceModeRequest,
|
||||||
PerformanceMode,
|
PerformanceMode,
|
||||||
|
)
|
||||||
),
|
),
|
||||||
"/braiins.bos.v1.PerformanceService/RemoveTunedProfiles": grpclib.const.Handler(
|
"/braiins.bos.v1.PerformanceService/RemoveTunedProfiles": (
|
||||||
|
grpclib.const.Handler(
|
||||||
self.__rpc_remove_tuned_profiles,
|
self.__rpc_remove_tuned_profiles,
|
||||||
grpclib.const.Cardinality.UNARY_UNARY,
|
grpclib.const.Cardinality.UNARY_UNARY,
|
||||||
RemoveTunedProfilesRequest,
|
RemoveTunedProfilesRequest,
|
||||||
RemoveTunedProfilesResponse,
|
RemoveTunedProfilesResponse,
|
||||||
|
)
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2836,17 +2862,21 @@ class ConfigurationServiceBase(ServiceBase):
|
|||||||
|
|
||||||
def __mapping__(self) -> Dict[str, grpclib.const.Handler]:
|
def __mapping__(self) -> Dict[str, grpclib.const.Handler]:
|
||||||
return {
|
return {
|
||||||
"/braiins.bos.v1.ConfigurationService/GetMinerConfiguration": grpclib.const.Handler(
|
"/braiins.bos.v1.ConfigurationService/GetMinerConfiguration": (
|
||||||
|
grpclib.const.Handler(
|
||||||
self.__rpc_get_miner_configuration,
|
self.__rpc_get_miner_configuration,
|
||||||
grpclib.const.Cardinality.UNARY_UNARY,
|
grpclib.const.Cardinality.UNARY_UNARY,
|
||||||
GetMinerConfigurationRequest,
|
GetMinerConfigurationRequest,
|
||||||
GetMinerConfigurationResponse,
|
GetMinerConfigurationResponse,
|
||||||
|
)
|
||||||
),
|
),
|
||||||
"/braiins.bos.v1.ConfigurationService/GetConstraints": grpclib.const.Handler(
|
"/braiins.bos.v1.ConfigurationService/GetConstraints": (
|
||||||
|
grpclib.const.Handler(
|
||||||
self.__rpc_get_constraints,
|
self.__rpc_get_constraints,
|
||||||
grpclib.const.Cardinality.UNARY_UNARY,
|
grpclib.const.Cardinality.UNARY_UNARY,
|
||||||
GetConstraintsRequest,
|
GetConstraintsRequest,
|
||||||
GetConstraintsResponse,
|
GetConstraintsResponse,
|
||||||
|
)
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "pyasic"
|
name = "pyasic"
|
||||||
version = "0.44.0"
|
version = "0.46.1"
|
||||||
description = "A simplified and standardized interface for Bitcoin ASICs."
|
description = "A simplified and standardized interface for Bitcoin ASICs."
|
||||||
authors = ["UpstreamData <brett@upstreamdata.ca>"]
|
authors = ["UpstreamData <brett@upstreamdata.ca>"]
|
||||||
repository = "https://github.com/UpstreamData/pyasic"
|
repository = "https://github.com/UpstreamData/pyasic"
|
||||||
@@ -9,11 +9,11 @@ readme = "README.md"
|
|||||||
|
|
||||||
[tool.poetry.dependencies]
|
[tool.poetry.dependencies]
|
||||||
python = "^3.8"
|
python = "^3.8"
|
||||||
httpx = "^0.25.2"
|
httpx = "^0.26.0"
|
||||||
asyncssh = "^2.14.1"
|
asyncssh = "^2.14.2"
|
||||||
grpc-requests = "^0.1.12"
|
grpc-requests = "^0.1.13"
|
||||||
passlib = "^1.7.4"
|
passlib = "^1.7.4"
|
||||||
pyaml = "^23.9.7"
|
pyaml = "^23.12.0"
|
||||||
toml = "^0.10.2"
|
toml = "^0.10.2"
|
||||||
betterproto = "2.0.0b6"
|
betterproto = "2.0.0b6"
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import inspect
|
|||||||
import sys
|
import sys
|
||||||
import unittest
|
import unittest
|
||||||
import warnings
|
import warnings
|
||||||
|
from dataclasses import asdict
|
||||||
|
|
||||||
from pyasic.miners.backends import CGMiner # noqa
|
from pyasic.miners.backends import CGMiner # noqa
|
||||||
from pyasic.miners.base import BaseMiner
|
from pyasic.miners.base import BaseMiner
|
||||||
@@ -57,7 +58,6 @@ class MinersTest(unittest.TestCase):
|
|||||||
"mac",
|
"mac",
|
||||||
"model",
|
"model",
|
||||||
"expected_hashrate",
|
"expected_hashrate",
|
||||||
"pools",
|
|
||||||
"uptime",
|
"uptime",
|
||||||
"wattage",
|
"wattage",
|
||||||
"wattage_limit",
|
"wattage_limit",
|
||||||
@@ -72,7 +72,9 @@ class MinersTest(unittest.TestCase):
|
|||||||
miner_api=miner_api,
|
miner_api=miner_api,
|
||||||
):
|
):
|
||||||
miner = MINER_CLASSES[miner_model][miner_api]("127.0.0.1")
|
miner = MINER_CLASSES[miner_model][miner_api]("127.0.0.1")
|
||||||
miner_keys = sorted(list(miner.data_locations.keys()))
|
miner_keys = sorted(
|
||||||
|
[str(k) for k in asdict(miner.data_locations).keys()]
|
||||||
|
)
|
||||||
self.assertEqual(miner_keys, keys)
|
self.assertEqual(miner_keys, keys)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user