Compare commits
75 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
707cf8b848 | ||
|
|
170843aae7 | ||
|
|
f5acf9ec62 | ||
|
|
edaf89c73a | ||
|
|
ce34dfdde8 | ||
|
|
e45e51ce65 | ||
|
|
f1501718a3 | ||
|
|
831d6ee955 | ||
|
|
7be6596fdd | ||
|
|
928e0dd028 | ||
|
|
672e753afb | ||
|
|
269e6aac14 | ||
|
|
1a4f3f7dc7 | ||
|
|
b0337e8417 | ||
|
|
60f3687d02 | ||
|
|
a8c45cb95d | ||
|
|
aa9ba66f8e | ||
|
|
06cc84f16d | ||
|
|
067d5c98f5 | ||
|
|
b4b84c773f | ||
|
|
cd1768aae9 | ||
|
|
2ef85d3868 | ||
|
|
6f64cc5e0d | ||
|
|
d44907435c | ||
|
|
04ca75d00e | ||
|
|
b56e94ce8c | ||
|
|
e7d30aad84 | ||
|
|
194fb539a1 | ||
|
|
416ea2964b | ||
|
|
3234f7e06f | ||
|
|
8fb357544b | ||
|
|
34006941ad | ||
|
|
3c3c34c54b | ||
|
|
5a61a87766 | ||
|
|
ef9a026ee8 | ||
|
|
71c85e0603 | ||
|
|
c5224b808e | ||
|
|
e4c6d751a1 | ||
|
|
ff4dfa124b | ||
|
|
d0eb5119aa | ||
|
|
cfa51623c4 | ||
|
|
96bb56ebd1 | ||
|
|
cdd7beccbe | ||
|
|
1a544851df | ||
|
|
aa2dc5a53d | ||
|
|
361d6e07cc | ||
|
|
53a018f526 | ||
|
|
6c9a378eee | ||
|
|
be67ef3471 | ||
|
|
a094d28a36 | ||
|
|
4156f93c0d | ||
|
|
ed6eb11653 | ||
|
|
39299f2cfa | ||
|
|
c80ca1415a | ||
|
|
a8428a2739 | ||
|
|
895fb1b43e | ||
|
|
014896ae1b | ||
|
|
84ac991685 | ||
|
|
bb481553fa | ||
|
|
7ab3d8b54e | ||
|
|
36494f2aca | ||
|
|
bea44a72ea | ||
|
|
9da7b44177 | ||
|
|
e7f05f7a28 | ||
|
|
2d229be9fd | ||
|
|
de5038e57a | ||
|
|
8ad1b3f72a | ||
|
|
070fb26dbc | ||
|
|
80d9d7df1d | ||
|
|
928c24f56f | ||
|
|
6e7442f90d | ||
|
|
936474ed3b | ||
|
|
2e28060e05 | ||
|
|
07f92557c6 | ||
|
|
6f6f5743cf |
@@ -1,6 +1,6 @@
|
||||
# pyasic
|
||||
## Miner Data
|
||||
|
||||
## Miner Data
|
||||
::: pyasic.data.MinerData
|
||||
handler: python
|
||||
options:
|
||||
@@ -13,3 +13,10 @@
|
||||
options:
|
||||
show_root_heading: false
|
||||
heading_level: 4
|
||||
|
||||
## Fan Data
|
||||
::: pyasic.data.Fan
|
||||
handler: python
|
||||
options:
|
||||
show_root_heading: false
|
||||
heading_level: 4
|
||||
|
||||
@@ -2,9 +2,8 @@
|
||||
## A10X Models
|
||||
|
||||
## A10X
|
||||
::: pyasic.miners.innosilicon.cgminer.A10X.A10X.CGMinerA10X
|
||||
::: pyasic.miners.innosilicon.cgminer.A10X.A10X.InnosiliconA10X
|
||||
handler: python
|
||||
options:
|
||||
show_root_heading: false
|
||||
heading_level: 4
|
||||
|
||||
|
||||
@@ -2,9 +2,8 @@
|
||||
## T3X Models
|
||||
|
||||
## T3H+
|
||||
::: pyasic.miners.innosilicon.cgminer.T3X.T3H.CGMinerT3HPlus
|
||||
::: pyasic.miners.innosilicon.cgminer.T3X.T3H.InnosiliconT3HPlus
|
||||
handler: python
|
||||
options:
|
||||
show_root_heading: false
|
||||
heading_level: 4
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
jinja2<3.1.0
|
||||
jinja2<3.1.3
|
||||
mkdocs
|
||||
mkdocstrings[python]
|
||||
|
||||
@@ -263,6 +263,12 @@ If you are sure you want to use this command please use API.send_command("{comma
|
||||
else:
|
||||
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"]:
|
||||
return False, data["Msg"]
|
||||
else:
|
||||
|
||||
@@ -48,10 +48,10 @@ PrePowerOnMessage = Union[
|
||||
|
||||
|
||||
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
|
||||
'\s*\$(\d+)\$([\w\./]*)\$'. If this format is not used, a
|
||||
\s*\$(\d+)\$([\w\./]*)\$. If this format is not used, a
|
||||
ValueError is raised.
|
||||
|
||||
Parameters:
|
||||
@@ -62,7 +62,7 @@ def _crypt(word: str, salt: str) -> str:
|
||||
An MD5 hash of the word with 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
|
||||
match = standard_salt.match(salt)
|
||||
# if the matching fails, the salt is incorrect
|
||||
|
||||
@@ -29,7 +29,7 @@ from pyasic.data import (
|
||||
)
|
||||
from pyasic.errors import APIError, APIWarning
|
||||
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_listener import MinerListener
|
||||
from pyasic.network import MinerNetwork
|
||||
@@ -50,6 +50,7 @@ __all__ = [
|
||||
"APIWarning",
|
||||
"get_miner",
|
||||
"AnyMiner",
|
||||
"DataOptions",
|
||||
"MinerFactory",
|
||||
"miner_factory",
|
||||
"MinerListener",
|
||||
|
||||
@@ -99,13 +99,13 @@ class MinerConfig:
|
||||
**self.power_scaling.as_bosminer(),
|
||||
}
|
||||
|
||||
def as_bos_grpc(self, user_suffix: str = None) -> dict:
|
||||
def as_boser(self, user_suffix: str = None) -> dict:
|
||||
return {
|
||||
**self.fan_mode.as_bos_grpc(),
|
||||
**self.temperature.as_bos_grpc(),
|
||||
**self.mining_mode.as_bos_grpc(),
|
||||
**self.pools.as_bos_grpc(user_suffix=user_suffix),
|
||||
**self.power_scaling.as_bos_grpc(),
|
||||
**self.fan_mode.as_boser(),
|
||||
**self.temperature.as_boser(),
|
||||
**self.mining_mode.as_boser(),
|
||||
**self.pools.as_boser(user_suffix=user_suffix),
|
||||
**self.power_scaling.as_boser(),
|
||||
}
|
||||
|
||||
def as_epic(self, user_suffix: str = None) -> dict:
|
||||
@@ -161,6 +161,34 @@ class MinerConfig:
|
||||
power_scaling=PowerScalingConfig.from_bosminer(toml_conf),
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_boser(cls, grpc_miner_conf: dict) -> "MinerConfig":
|
||||
return cls(
|
||||
pools=PoolConfig.from_boser(grpc_miner_conf),
|
||||
mining_mode=MiningModeConfig.from_boser(grpc_miner_conf),
|
||||
fan_mode=FanModeConfig.from_boser(grpc_miner_conf),
|
||||
temperature=TemperatureConfig.from_boser(grpc_miner_conf),
|
||||
power_scaling=PowerScalingConfig.from_boser(grpc_miner_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:
|
||||
result = deepcopy(a)
|
||||
|
||||
@@ -44,12 +44,15 @@ class MinerConfigOption(Enum):
|
||||
def as_bosminer(self) -> dict:
|
||||
return self.value.as_bosminer()
|
||||
|
||||
def as_bos_grpc(self) -> dict:
|
||||
return self.value.as_bos_grpc()
|
||||
def as_boser(self) -> dict:
|
||||
return self.value.as_boser()
|
||||
|
||||
def as_epic(self) -> dict:
|
||||
return self.value.as_epic()
|
||||
|
||||
def as_vnish(self) -> dict:
|
||||
return self.value.as_vnish()
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
return self.value(*args, **kwargs)
|
||||
|
||||
@@ -88,8 +91,11 @@ class MinerConfigValue:
|
||||
def as_bosminer(self) -> dict:
|
||||
return {}
|
||||
|
||||
def as_bos_grpc(self) -> dict:
|
||||
def as_boser(self) -> dict:
|
||||
return {}
|
||||
|
||||
def as_epic(self) -> dict:
|
||||
return {}
|
||||
|
||||
def as_vnish(self) -> dict:
|
||||
return {}
|
||||
|
||||
@@ -22,10 +22,26 @@ from pyasic.config.base import MinerConfigOption, MinerConfigValue
|
||||
@dataclass
|
||||
class FanModeNormal(MinerConfigValue):
|
||||
mode: str = field(init=False, default="normal")
|
||||
minimum_fans: int = 1
|
||||
minimum_speed: int = 0
|
||||
|
||||
@classmethod
|
||||
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:
|
||||
return {"bitmain-fan-ctrl": False, "bitmain-fan-pwn": "100"}
|
||||
@@ -58,6 +74,15 @@ class FanModeManual(MinerConfigValue):
|
||||
cls_conf["speed"] = toml_fan_conf["speed"]
|
||||
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:
|
||||
return {"bitmain-fan-ctrl": True, "bitmain-fan-pwn": str(self.speed)}
|
||||
|
||||
@@ -116,6 +141,17 @@ class FanModeConfig(MinerConfigOption):
|
||||
else:
|
||||
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
|
||||
def from_bosminer(cls, toml_conf: dict):
|
||||
if toml_conf.get("temp_control") is None:
|
||||
@@ -132,3 +168,37 @@ class FanModeConfig(MinerConfigOption):
|
||||
return cls.manual()
|
||||
elif mode == "disabled":
|
||||
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()
|
||||
|
||||
@classmethod
|
||||
def from_boser(cls, grpc_miner_conf: dict):
|
||||
try:
|
||||
temperature_conf = grpc_miner_conf["temperature"]
|
||||
except LookupError:
|
||||
return cls.default()
|
||||
|
||||
keys = temperature_conf.keys()
|
||||
if "auto" in keys:
|
||||
if "minimumRequiredFans" in keys:
|
||||
return cls.normal(temperature_conf["minimumRequiredFans"])
|
||||
return cls.normal()
|
||||
if "manual" in keys:
|
||||
conf = {}
|
||||
if "fanSpeedRatio" in temperature_conf["manual"].keys():
|
||||
conf["speed"] = int(temperature_conf["manual"]["fanSpeedRatio"])
|
||||
if "minimumRequiredFans" in keys:
|
||||
conf["minimum_fans"] = int(temperature_conf["minimumRequiredFans"])
|
||||
return cls.manual(**conf)
|
||||
|
||||
@@ -14,9 +14,19 @@
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Union
|
||||
from typing import Dict, Union
|
||||
|
||||
from pyasic.config.base import MinerConfigOption, MinerConfigValue
|
||||
from pyasic.web.braiins_os.proto.braiins.bos.v1 import (
|
||||
HashrateTargetMode,
|
||||
PerformanceMode,
|
||||
Power,
|
||||
PowerTargetMode,
|
||||
SaveAction,
|
||||
SetPerformanceModeRequest,
|
||||
TeraHashrate,
|
||||
TunerPerformanceMode,
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -99,6 +109,20 @@ class MiningModePowerTune(MinerConfigValue):
|
||||
def as_bosminer(self) -> dict:
|
||||
return {"autotuning": {"enabled": True, "psu_power_limit": self.power}}
|
||||
|
||||
def as_boser(self) -> dict:
|
||||
return {
|
||||
"set_performance_mode": SetPerformanceModeRequest(
|
||||
save_action=SaveAction.SAVE_ACTION_SAVE_AND_APPLY,
|
||||
mode=PerformanceMode(
|
||||
tuner_mode=TunerPerformanceMode(
|
||||
power_target=PowerTargetMode(
|
||||
power_target=Power(watt=self.power)
|
||||
)
|
||||
)
|
||||
),
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
@dataclass
|
||||
class MiningModeHashrateTune(MinerConfigValue):
|
||||
@@ -112,6 +136,22 @@ class MiningModeHashrateTune(MinerConfigValue):
|
||||
def as_am_modern(self) -> dict:
|
||||
return {"miner-mode": "0"}
|
||||
|
||||
def as_boser(self) -> dict:
|
||||
return {
|
||||
"set_performance_mode": SetPerformanceModeRequest(
|
||||
save_action=SaveAction.SAVE_ACTION_SAVE_AND_APPLY,
|
||||
mode=PerformanceMode(
|
||||
tuner_mode=TunerPerformanceMode(
|
||||
hashrate_target=HashrateTargetMode(
|
||||
hashrate_target=TeraHashrate(
|
||||
terahash_per_second=self.hashrate
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@dataclass
|
||||
class ManualBoardSettings(MinerConfigValue):
|
||||
@@ -132,7 +172,7 @@ class MiningModeManual(MinerConfigValue):
|
||||
|
||||
global_freq: float
|
||||
global_volt: float
|
||||
boards: dict[int, ManualBoardSettings] = field(default_factory=dict)
|
||||
boards: Dict[int, ManualBoardSettings] = field(default_factory=dict)
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, dict_conf: Union[dict, None]) -> "MiningModeManual":
|
||||
@@ -145,6 +185,20 @@ class MiningModeManual(MinerConfigValue):
|
||||
def as_am_modern(self) -> dict:
|
||||
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):
|
||||
normal = MiningModeNormal
|
||||
@@ -186,6 +240,29 @@ class MiningModeConfig(MinerConfigOption):
|
||||
return cls.low()
|
||||
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
|
||||
def from_bosminer(cls, toml_conf: dict):
|
||||
if toml_conf.get("autotuning") is None:
|
||||
@@ -211,3 +288,45 @@ class MiningModeConfig(MinerConfigOption):
|
||||
if autotuning_conf.get("hashrate_target") is not None:
|
||||
return cls.hashrate_tuning(autotuning_conf["hashrate_target"])
|
||||
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"]))
|
||||
|
||||
@classmethod
|
||||
def from_boser(cls, grpc_miner_conf: dict):
|
||||
try:
|
||||
tuner_conf = grpc_miner_conf["tuner"]
|
||||
if not tuner_conf.get("enabled", False):
|
||||
return cls.default()
|
||||
except LookupError:
|
||||
return cls.default()
|
||||
|
||||
if tuner_conf.get("tunerMode") is not None:
|
||||
if tuner_conf["tunerMode"] == 1:
|
||||
if tuner_conf.get("powerTarget") is not None:
|
||||
return cls.power_tuning(tuner_conf["powerTarget"]["watt"])
|
||||
return cls.power_tuning()
|
||||
|
||||
if tuner_conf["tunerMode"] == 2:
|
||||
if tuner_conf.get("hashrateTarget") is not None:
|
||||
return cls.hashrate_tuning(
|
||||
int(tuner_conf["hashrateTarget"]["terahashPerSecond"])
|
||||
)
|
||||
return cls.hashrate_tuning()
|
||||
|
||||
if tuner_conf.get("powerTarget") is not None:
|
||||
return cls.power_tuning(tuner_conf["powerTarget"]["watt"])
|
||||
|
||||
if tuner_conf.get("hashrateTarget") is not None:
|
||||
return cls.hashrate_tuning(
|
||||
int(tuner_conf["hashrateTarget"]["terahashPerSecond"])
|
||||
)
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
import random
|
||||
import string
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Union
|
||||
from typing import Dict, List, Union
|
||||
|
||||
from pyasic.config.base import MinerConfigValue
|
||||
|
||||
@@ -108,6 +108,12 @@ class Pool(MinerConfigValue):
|
||||
def from_api(cls, api_pool: dict) -> "Pool":
|
||||
return cls(url=api_pool["URL"], user=api_pool["User"], password="x")
|
||||
|
||||
@classmethod
|
||||
def from_epic(cls, api_pool: dict) -> "Pool":
|
||||
return cls(
|
||||
url=api_pool["pool"], user=api_pool["login"], password=api_pool["password"]
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_am_modern(cls, web_pool: dict) -> "Pool":
|
||||
return cls(
|
||||
@@ -135,10 +141,26 @@ class Pool(MinerConfigValue):
|
||||
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"],
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_boser(cls, grpc_pool: dict) -> "Pool":
|
||||
return cls(
|
||||
url=grpc_pool["url"],
|
||||
user=grpc_pool["user"],
|
||||
password=grpc_pool["password"],
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class PoolGroup(MinerConfigValue):
|
||||
pools: list[Pool] = field(default_factory=list)
|
||||
pools: List[Pool] = field(default_factory=list)
|
||||
quota: int = 1
|
||||
name: str = None
|
||||
|
||||
@@ -237,6 +259,13 @@ class PoolGroup(MinerConfigValue):
|
||||
pools.append(Pool.from_api(pool))
|
||||
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
|
||||
def from_am_modern(cls, web_pool_list: list) -> "PoolGroup":
|
||||
pools = []
|
||||
@@ -262,10 +291,27 @@ class PoolGroup(MinerConfigValue):
|
||||
)
|
||||
return cls()
|
||||
|
||||
@classmethod
|
||||
def from_vnish(cls, web_settings_pools: dict) -> "PoolGroup":
|
||||
return cls([Pool.from_vnish(p) for p in web_settings_pools])
|
||||
|
||||
@classmethod
|
||||
def from_boser(cls, grpc_pool_group: dict):
|
||||
try:
|
||||
return cls(
|
||||
pools=[Pool.from_boser(p) for p in grpc_pool_group["pools"]],
|
||||
name=grpc_pool_group["name"],
|
||||
quota=grpc_pool_group["quota"]["value"]
|
||||
if grpc_pool_group.get("quota") is not None
|
||||
else 1,
|
||||
)
|
||||
except LookupError:
|
||||
return cls()
|
||||
|
||||
|
||||
@dataclass
|
||||
class PoolConfig(MinerConfigValue):
|
||||
groups: list[PoolGroup] = field(default_factory=list)
|
||||
groups: List[PoolGroup] = field(default_factory=list)
|
||||
|
||||
@classmethod
|
||||
def default(cls) -> "PoolConfig":
|
||||
@@ -279,7 +325,7 @@ class PoolConfig(MinerConfigValue):
|
||||
return cls(groups=[PoolGroup.from_dict(g) for g in dict_conf["groups"]])
|
||||
|
||||
@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 = []
|
||||
for pool in pools:
|
||||
if isinstance(pool, dict):
|
||||
@@ -324,16 +370,24 @@ class PoolConfig(MinerConfigValue):
|
||||
}
|
||||
return {"group": [PoolGroup().as_bosminer()]}
|
||||
|
||||
def as_bos_grpc(self, user_suffix: str = None) -> dict:
|
||||
def as_boser(self, user_suffix: str = None) -> dict:
|
||||
return {}
|
||||
|
||||
@classmethod
|
||||
def from_api(cls, api_pools: dict) -> "PoolConfig":
|
||||
pool_data = api_pools["POOLS"]
|
||||
try:
|
||||
pool_data = api_pools["POOLS"]
|
||||
except KeyError:
|
||||
return PoolConfig.default()
|
||||
pool_data = sorted(pool_data, key=lambda x: int(x["POOL"]))
|
||||
|
||||
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
|
||||
def from_am_modern(cls, web_conf: dict) -> "PoolConfig":
|
||||
pool_data = web_conf["pools"]
|
||||
@@ -354,3 +408,22 @@ class PoolConfig(MinerConfigValue):
|
||||
return cls()
|
||||
|
||||
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()
|
||||
|
||||
@classmethod
|
||||
def from_boser(cls, grpc_miner_conf: dict):
|
||||
try:
|
||||
return cls(
|
||||
groups=[
|
||||
PoolGroup.from_boser(group)
|
||||
for group in grpc_miner_conf["poolGroups"]
|
||||
]
|
||||
)
|
||||
except LookupError:
|
||||
return cls()
|
||||
|
||||
@@ -17,7 +17,12 @@ from dataclasses import dataclass, field
|
||||
from typing import Union
|
||||
|
||||
from pyasic.config.base import MinerConfigOption, MinerConfigValue
|
||||
from pyasic.web.bosminer.proto.braiins.bos.v1 import DpsPowerTarget, DpsTarget, Hours
|
||||
from pyasic.web.braiins_os.proto.braiins.bos.v1 import (
|
||||
DpsPowerTarget,
|
||||
DpsTarget,
|
||||
Power,
|
||||
SetDpsRequest,
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -37,13 +42,8 @@ class PowerScalingShutdownEnabled(MinerConfigValue):
|
||||
|
||||
return cfg
|
||||
|
||||
def as_bos_grpc(self) -> dict:
|
||||
cfg = {"enable_shutdown ": True}
|
||||
|
||||
if self.duration is not None:
|
||||
cfg["shutdown_duration"] = Hours(self.duration)
|
||||
|
||||
return cfg
|
||||
def as_boser(self) -> dict:
|
||||
return {"enable_shutdown": True, "shutdown_duration": self.duration}
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -57,7 +57,7 @@ class PowerScalingShutdownDisabled(MinerConfigValue):
|
||||
def as_bosminer(self) -> dict:
|
||||
return {"shutdown_enabled": False}
|
||||
|
||||
def as_bos_grpc(self) -> dict:
|
||||
def as_boser(self) -> dict:
|
||||
return {"enable_shutdown ": False}
|
||||
|
||||
|
||||
@@ -88,6 +88,19 @@ class PowerScalingShutdown(MinerConfigOption):
|
||||
return cls.disabled()
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def from_boser(cls, power_scaling_conf: dict):
|
||||
sd_enabled = power_scaling_conf.get("shutdownEnabled")
|
||||
if sd_enabled is not None:
|
||||
if sd_enabled:
|
||||
try:
|
||||
return cls.enabled(power_scaling_conf["shutdownDuration"]["hours"])
|
||||
except KeyError:
|
||||
return cls.enabled()
|
||||
else:
|
||||
return cls.disabled()
|
||||
return None
|
||||
|
||||
|
||||
@dataclass
|
||||
class PowerScalingEnabled(MinerConfigValue):
|
||||
@@ -133,20 +146,19 @@ class PowerScalingEnabled(MinerConfigValue):
|
||||
|
||||
return {"power_scaling": cfg}
|
||||
|
||||
def as_bos_grpc(self) -> dict:
|
||||
cfg = {"enable": True}
|
||||
target_conf = {}
|
||||
if self.power_step is not None:
|
||||
target_conf["power_step"] = self.power_step
|
||||
if self.minimum_power is not None:
|
||||
target_conf["min_power_target"] = self.minimum_power
|
||||
|
||||
cfg["target"] = DpsTarget(power_target=DpsPowerTarget(**target_conf))
|
||||
|
||||
if self.shutdown_enabled is not None:
|
||||
cfg = {**cfg, **self.shutdown_enabled.as_bos_grpc()}
|
||||
|
||||
return {"dps": cfg}
|
||||
def as_boser(self) -> dict:
|
||||
return {
|
||||
"set_dps": SetDpsRequest(
|
||||
enable=True,
|
||||
**self.shutdown_enabled.as_boser(),
|
||||
target=DpsTarget(
|
||||
power_target=DpsPowerTarget(
|
||||
power_step=Power(self.power_step),
|
||||
min_power_target=Power(self.minimum_power),
|
||||
)
|
||||
),
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -187,3 +199,20 @@ class PowerScalingConfig(MinerConfigOption):
|
||||
return cls.disabled()
|
||||
|
||||
return cls.default()
|
||||
|
||||
@classmethod
|
||||
def from_boser(cls, grpc_miner_conf: dict):
|
||||
try:
|
||||
dps_conf = grpc_miner_conf["dps"]
|
||||
if not dps_conf.get("enabled", False):
|
||||
return cls.disabled()
|
||||
except LookupError:
|
||||
return cls.default()
|
||||
|
||||
conf = {"shutdown_enabled": PowerScalingShutdown.from_boser(dps_conf)}
|
||||
|
||||
if dps_conf.get("minPowerTarget") is not None:
|
||||
conf["minimum_power"] = dps_conf["minPowerTarget"]["watt"]
|
||||
if dps_conf.get("powerStep") is not None:
|
||||
conf["power_step"] = dps_conf["powerStep"]["watt"]
|
||||
return cls.enabled(**conf)
|
||||
|
||||
@@ -56,3 +56,58 @@ class TemperatureConfig(MinerConfigValue):
|
||||
hot=temp_control.get("hot_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()
|
||||
|
||||
@classmethod
|
||||
def from_boser(cls, grpc_miner_conf: dict):
|
||||
try:
|
||||
temperature_conf = grpc_miner_conf["temperature"]
|
||||
except KeyError:
|
||||
return cls.default()
|
||||
|
||||
root_key = None
|
||||
for key in ["auto", "manual", "disabled"]:
|
||||
if key in temperature_conf.keys():
|
||||
root_key = key
|
||||
break
|
||||
if root_key is None:
|
||||
return cls.default()
|
||||
|
||||
conf = {}
|
||||
keys = temperature_conf[root_key].keys()
|
||||
if "targetTemperature" in keys:
|
||||
conf["target"] = int(
|
||||
temperature_conf[root_key]["targetTemperature"]["degreeC"]
|
||||
)
|
||||
if "hotTemperature" in keys:
|
||||
conf["hot"] = int(temperature_conf[root_key]["hotTemperature"]["degreeC"])
|
||||
if "dangerousTemperature" in keys:
|
||||
conf["danger"] = int(
|
||||
temperature_conf[root_key]["dangerousTemperature"]["degreeC"]
|
||||
)
|
||||
|
||||
return cls(**conf)
|
||||
return cls.default()
|
||||
|
||||
@@ -39,6 +39,7 @@ class HashBoard:
|
||||
chip_temp: The temperature of the chips as an int.
|
||||
chips: The chip count of the board as an int.
|
||||
expected_chips: The expected chip count of the board as an int.
|
||||
serial_number: The serial number of the board.
|
||||
missing: Whether the board is returned from the miners data as a bool.
|
||||
"""
|
||||
|
||||
@@ -48,6 +49,7 @@ class HashBoard:
|
||||
chip_temp: int = None
|
||||
chips: int = None
|
||||
expected_chips: int = None
|
||||
serial_number: str = None
|
||||
missing: bool = True
|
||||
|
||||
def get(self, __key: str, default: Any = None):
|
||||
@@ -109,7 +111,7 @@ class MinerData:
|
||||
hashrate: The hashrate of the miner in TH/s as a float. Calculated automatically.
|
||||
_hashrate: Backup for hashrate found via API instead of hashboards.
|
||||
expected_hashrate: The factory nominal hashrate of the miner in TH/s as a float.
|
||||
hashboards: A list of hashboards on the miner with their statistics.
|
||||
hashboards: A list of [`HashBoard`][pyasic.data.HashBoard]s on the miner with their statistics.
|
||||
temperature_avg: The average temperature across the boards. Calculated automatically.
|
||||
env_temp: The environment temps as a float.
|
||||
wattage: Current power draw of the miner as an int.
|
||||
@@ -122,11 +124,7 @@ class MinerData:
|
||||
percent_expected_hashrate: The percent of total hashrate out of the expected hashrate. Calculated automatically.
|
||||
percent_expected_wattage: The percent of total wattage out of the expected wattage. Calculated automatically.
|
||||
nominal: Whether the number of chips in the miner is nominal. Calculated automatically.
|
||||
pool_split: The pool split as a str.
|
||||
pool_1_url: The first pool url on the miner as a str.
|
||||
pool_1_user: The first pool user on the miner as a str.
|
||||
pool_2_url: The second pool url on the miner as a str.
|
||||
pool_2_user: The second pool user on the miner as a str.
|
||||
config: The parsed config of the miner, using [`MinerConfig`][pyasic.config.MinerConfig].
|
||||
errors: A list of errors on the miner.
|
||||
fault_light: Whether the fault light is on as a boolean.
|
||||
efficiency: Efficiency of the miner in J/TH (Watts per TH/s). Calculated automatically.
|
||||
|
||||
@@ -66,14 +66,14 @@ class _MinerPhaseBalancer:
|
||||
str(miner.ip): {
|
||||
"miner": miner,
|
||||
"set": 0,
|
||||
"min": miner.fan_count * FAN_USAGE,
|
||||
"min": miner.expected_fans * FAN_USAGE,
|
||||
}
|
||||
for miner in miners
|
||||
}
|
||||
for miner in miners:
|
||||
if (
|
||||
isinstance(miner, BTMiner)
|
||||
and not (miner.model.startswith("M2") if miner.model else True)
|
||||
and not (miner.raw_model.startswith("M2") if miner.raw_model else True)
|
||||
) or isinstance(miner, BOSMiner):
|
||||
if isinstance(miner, S9):
|
||||
self.miners[str(miner.ip)]["tune"] = True
|
||||
@@ -98,8 +98,8 @@ class _MinerPhaseBalancer:
|
||||
self.miners[str(miner.ip)]["tune"] = False
|
||||
self.miners[str(miner.ip)]["shutdown"] = True
|
||||
self.miners[str(miner.ip)]["max"] = 3600
|
||||
if miner.model:
|
||||
if miner.model.startswith("M2"):
|
||||
if miner.raw_model:
|
||||
if miner.raw_model.startswith("M2"):
|
||||
self.miners[str(miner.ip)]["tune"] = False
|
||||
self.miners[str(miner.ip)]["shutdown"] = True
|
||||
self.miners[str(miner.ip)]["max"] = 2400
|
||||
|
||||
@@ -14,21 +14,21 @@
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
from pyasic.miners.backends import BOSMiner
|
||||
from pyasic.miners.backends import BOSer
|
||||
from pyasic.miners.types import S17, S17e, S17Plus, S17Pro
|
||||
|
||||
|
||||
class BOSMinerS17(BOSMiner, S17):
|
||||
class BOSMinerS17(BOSer, S17):
|
||||
pass
|
||||
|
||||
|
||||
class BOSMinerS17Plus(BOSMiner, S17Plus):
|
||||
class BOSMinerS17Plus(BOSer, S17Plus):
|
||||
pass
|
||||
|
||||
|
||||
class BOSMinerS17Pro(BOSMiner, S17Pro):
|
||||
class BOSMinerS17Pro(BOSer, S17Pro):
|
||||
pass
|
||||
|
||||
|
||||
class BOSMinerS17e(BOSMiner, S17e):
|
||||
class BOSMinerS17e(BOSer, S17e):
|
||||
pass
|
||||
|
||||
@@ -14,17 +14,17 @@
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
from pyasic.miners.backends import BOSMiner
|
||||
from pyasic.miners.backends import BOSer
|
||||
from pyasic.miners.types import T17, T17e, T17Plus
|
||||
|
||||
|
||||
class BOSMinerT17(BOSMiner, T17):
|
||||
class BOSMinerT17(BOSer, T17):
|
||||
pass
|
||||
|
||||
|
||||
class BOSMinerT17Plus(BOSMiner, T17Plus):
|
||||
class BOSMinerT17Plus(BOSer, T17Plus):
|
||||
pass
|
||||
|
||||
|
||||
class BOSMinerT17e(BOSMiner, T17e):
|
||||
class BOSMinerT17e(BOSer, T17e):
|
||||
pass
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
from pyasic.miners.backends import BOSMiner
|
||||
from pyasic.miners.backends import BOSer
|
||||
from pyasic.miners.types import (
|
||||
S19,
|
||||
S19XP,
|
||||
@@ -30,45 +30,45 @@ from pyasic.miners.types import (
|
||||
)
|
||||
|
||||
|
||||
class BOSMinerS19(BOSMiner, S19):
|
||||
class BOSMinerS19(BOSer, S19):
|
||||
pass
|
||||
|
||||
|
||||
class BOSMinerS19Plus(BOSMiner, S19Plus):
|
||||
class BOSMinerS19Plus(BOSer, S19Plus):
|
||||
pass
|
||||
|
||||
|
||||
class BOSMinerS19Pro(BOSMiner, S19Pro):
|
||||
class BOSMinerS19Pro(BOSer, S19Pro):
|
||||
pass
|
||||
|
||||
|
||||
class BOSMinerS19a(BOSMiner, S19a):
|
||||
class BOSMinerS19a(BOSer, S19a):
|
||||
pass
|
||||
|
||||
|
||||
class BOSMinerS19j(BOSMiner, S19j):
|
||||
class BOSMinerS19j(BOSer, S19j):
|
||||
pass
|
||||
|
||||
|
||||
class BOSMinerS19jNoPIC(BOSMiner, S19jNoPIC):
|
||||
class BOSMinerS19jNoPIC(BOSer, S19jNoPIC):
|
||||
pass
|
||||
|
||||
|
||||
class BOSMinerS19jPro(BOSMiner, S19jPro):
|
||||
class BOSMinerS19jPro(BOSer, S19jPro):
|
||||
pass
|
||||
|
||||
|
||||
class BOSMinerS19kProNoPIC(BOSMiner, S19kProNoPIC):
|
||||
class BOSMinerS19kProNoPIC(BOSer, S19kProNoPIC):
|
||||
pass
|
||||
|
||||
|
||||
class BOSMinerS19aPro(BOSMiner, S19aPro):
|
||||
class BOSMinerS19aPro(BOSer, S19aPro):
|
||||
pass
|
||||
|
||||
|
||||
class BOSMinerS19jProPlus(BOSMiner, S19jProPlus):
|
||||
class BOSMinerS19jProPlus(BOSer, S19jProPlus):
|
||||
pass
|
||||
|
||||
|
||||
class BOSMinerS19XP(BOSMiner, S19XP):
|
||||
class BOSMinerS19XP(BOSer, S19XP):
|
||||
pass
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
from pyasic.miners.backends import BOSMiner
|
||||
from pyasic.miners.backends import BOSer
|
||||
from pyasic.miners.types import T19
|
||||
|
||||
|
||||
class BOSMinerT19(BOSMiner, T19):
|
||||
class BOSMinerT19(BOSer, T19):
|
||||
pass
|
||||
|
||||
@@ -25,10 +25,6 @@ from pyasic.miners.types import T9
|
||||
|
||||
|
||||
class HiveonT9(Hiveon, T9):
|
||||
def __init__(self, ip: str, api_ver: str = "0.0.0") -> None:
|
||||
super().__init__(ip, api_ver=api_ver)
|
||||
self.ip = ip
|
||||
self.pwd = "admin"
|
||||
|
||||
##################################################
|
||||
### DATA GATHERING FUNCTIONS (get_{some_data}) ###
|
||||
@@ -45,39 +41,49 @@ class HiveonT9(Hiveon, T9):
|
||||
except (TypeError, ValueError, asyncssh.Error, OSError, AttributeError):
|
||||
pass
|
||||
|
||||
async def get_hashboards(self, api_stats: dict = None) -> List[HashBoard]:
|
||||
async def _get_hashboards(self, api_stats: dict = None) -> List[HashBoard]:
|
||||
hashboards = [
|
||||
HashBoard(slot=board, expected_chips=self.expected_chips)
|
||||
for board in range(self.expected_hashboards)
|
||||
]
|
||||
|
||||
if api_stats is None:
|
||||
try:
|
||||
api_stats = self.api.stats()
|
||||
except APIError:
|
||||
return []
|
||||
|
||||
board_map = {
|
||||
0: [2, 9, 10],
|
||||
1: [3, 11, 12],
|
||||
2: [4, 13, 14],
|
||||
}
|
||||
hashboards = []
|
||||
|
||||
for board in board_map:
|
||||
hashboard = HashBoard(slot=board, expected_chips=self.expected_chips)
|
||||
hashrate = 0
|
||||
chips = 0
|
||||
for chipset in board_map[board]:
|
||||
if hashboard.chip_temp == None:
|
||||
if hashboards[board].chip_temp is None:
|
||||
try:
|
||||
hashboard.board_temp = api_stats["STATS"][1][f"temp{chipset}"]
|
||||
hashboard.chip_temp = api_stats["STATS"][1][f"temp2_{chipset}"]
|
||||
hashboards[board].temp = api_stats["STATS"][1][f"temp{chipset}"]
|
||||
hashboards[board].chip_temp = api_stats["STATS"][1][
|
||||
f"temp2_{chipset}"
|
||||
]
|
||||
except (KeyError, IndexError):
|
||||
pass
|
||||
else:
|
||||
hashboard.missing = False
|
||||
hashboards[board].missing = False
|
||||
try:
|
||||
hashrate += api_stats["STATS"][1][f"chain_rate{chipset}"]
|
||||
chips += api_stats["STATS"][1][f"chain_acn{chipset}"]
|
||||
except (KeyError, IndexError):
|
||||
pass
|
||||
hashboard.hashrate = round(hashrate / 1000, 2)
|
||||
hashboard.chips = chips
|
||||
hashboards.append(hashboard)
|
||||
hashboards[board].hashrate = round(hashrate / 1000, 2)
|
||||
hashboards[board].chips = chips
|
||||
|
||||
return hashboards
|
||||
|
||||
async def get_wattage(self, api_stats: dict = None) -> Optional[int]:
|
||||
async def _get_wattage(self, api_stats: dict = None) -> Optional[int]:
|
||||
if not api_stats:
|
||||
try:
|
||||
api_stats = await self.api.stats()
|
||||
@@ -94,7 +100,7 @@ class HiveonT9(Hiveon, T9):
|
||||
# parse wattage position out of raw data
|
||||
return round(float(wattage_raw.split(" ")[0]))
|
||||
|
||||
async def get_env_temp(self, api_stats: dict = None) -> Optional[float]:
|
||||
async def _get_env_temp(self, api_stats: dict = None) -> Optional[float]:
|
||||
env_temp_list = []
|
||||
board_map = {
|
||||
0: [2, 9, 10],
|
||||
|
||||
@@ -17,7 +17,7 @@ from .antminer import AntminerModern, AntminerOld
|
||||
from .bfgminer import BFGMiner
|
||||
from .bfgminer_goldshell import BFGMinerGoldshell
|
||||
from .bmminer import BMMiner
|
||||
from .bosminer import BOSMiner
|
||||
from .braiins_os import BOSer, BOSMiner
|
||||
from .btminer import BTMiner
|
||||
from .cgminer import CGMiner
|
||||
from .cgminer_avalon import CGMinerAvalon
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
import asyncio
|
||||
from typing import List, Optional, Union
|
||||
|
||||
from pyasic.API import APIError
|
||||
@@ -23,50 +22,59 @@ from pyasic.data import Fan, HashBoard
|
||||
from pyasic.data.error_codes import MinerErrorData, X19Error
|
||||
from pyasic.miners.backends.bmminer import BMMiner
|
||||
from pyasic.miners.backends.cgminer import CGMiner
|
||||
from pyasic.miners.base import (
|
||||
DataFunction,
|
||||
DataLocations,
|
||||
DataOptions,
|
||||
RPCAPICommand,
|
||||
WebAPICommand,
|
||||
)
|
||||
from pyasic.web.antminer import AntminerModernWebAPI, AntminerOldWebAPI
|
||||
|
||||
ANTMINER_MODERN_DATA_LOC = {
|
||||
"mac": {
|
||||
"cmd": "get_mac",
|
||||
"kwargs": {"web_get_system_info": {"web": "get_system_info"}},
|
||||
},
|
||||
"model": {"cmd": "get_model", "kwargs": {}},
|
||||
"api_ver": {"cmd": "get_api_ver", "kwargs": {"api_version": {"api": "version"}}},
|
||||
"fw_ver": {"cmd": "get_fw_ver", "kwargs": {"api_version": {"api": "version"}}},
|
||||
"hostname": {
|
||||
"cmd": "get_hostname",
|
||||
"kwargs": {"web_get_system_info": {"web": "get_system_info"}},
|
||||
},
|
||||
"hashrate": {"cmd": "get_hashrate", "kwargs": {"api_summary": {"api": "summary"}}},
|
||||
"expected_hashrate": {
|
||||
"cmd": "get_expected_hashrate",
|
||||
"kwargs": {"api_stats": {"api": "stats"}},
|
||||
},
|
||||
"hashboards": {"cmd": "get_hashboards", "kwargs": {"api_stats": {"api": "stats"}}},
|
||||
"env_temp": {"cmd": "get_env_temp", "kwargs": {}},
|
||||
"wattage": {"cmd": "get_wattage", "kwargs": {}},
|
||||
"wattage_limit": {"cmd": "get_wattage_limit", "kwargs": {}},
|
||||
"fans": {"cmd": "get_fans", "kwargs": {"api_stats": {"api": "stats"}}},
|
||||
"fan_psu": {"cmd": "get_fan_psu", "kwargs": {}},
|
||||
"errors": {"cmd": "get_errors", "kwargs": {"web_summary": {"web": "summary"}}},
|
||||
"fault_light": {
|
||||
"cmd": "get_fault_light",
|
||||
"kwargs": {"web_get_blink_status": {"web": "get_blink_status"}},
|
||||
},
|
||||
"pools": {"cmd": "get_pools", "kwargs": {"api_pools": {"api": "pools"}}},
|
||||
"is_mining": {
|
||||
"cmd": "is_mining",
|
||||
"kwargs": {"web_get_conf": {"web": "get_miner_conf"}},
|
||||
},
|
||||
"uptime": {
|
||||
"cmd": "get_uptime",
|
||||
"kwargs": {"api_stats": {"api": "stats"}},
|
||||
},
|
||||
"config": {
|
||||
"cmd": "get_config",
|
||||
"kwargs": {},
|
||||
},
|
||||
}
|
||||
ANTMINER_MODERN_DATA_LOC = DataLocations(
|
||||
**{
|
||||
str(DataOptions.MAC): DataFunction(
|
||||
"_get_mac", [WebAPICommand("web_get_system_info", "get_system_info")]
|
||||
),
|
||||
str(DataOptions.API_VERSION): DataFunction(
|
||||
"_get_api_ver", [RPCAPICommand("api_version", "version")]
|
||||
),
|
||||
str(DataOptions.FW_VERSION): DataFunction(
|
||||
"_get_fw_ver", [RPCAPICommand("api_version", "version")]
|
||||
),
|
||||
str(DataOptions.HOSTNAME): DataFunction(
|
||||
"_get_hostname", [WebAPICommand("web_get_system_info", "get_system_info")]
|
||||
),
|
||||
str(DataOptions.HASHRATE): DataFunction(
|
||||
"_get_hashrate", [RPCAPICommand("api_summary", "summary")]
|
||||
),
|
||||
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
|
||||
"_get_expected_hashrate", [RPCAPICommand("api_stats", "stats")]
|
||||
),
|
||||
str(DataOptions.HASHBOARDS): DataFunction("_get_hashboards"),
|
||||
str(DataOptions.ENVIRONMENT_TEMP): DataFunction("_get_env_temp"),
|
||||
str(DataOptions.WATTAGE): DataFunction("_get_wattage"),
|
||||
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", [WebAPICommand("web_summary", "summary")]
|
||||
),
|
||||
str(DataOptions.FAULT_LIGHT): DataFunction(
|
||||
"_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 AntminerModern(BMMiner):
|
||||
@@ -132,7 +140,7 @@ class AntminerModern(BMMiner):
|
||||
await self.send_config(cfg)
|
||||
return True
|
||||
|
||||
async def get_hostname(self, web_get_system_info: dict = None) -> Union[str, None]:
|
||||
async def _get_hostname(self, web_get_system_info: dict = None) -> Union[str, None]:
|
||||
if not web_get_system_info:
|
||||
try:
|
||||
web_get_system_info = await self.web.get_system_info()
|
||||
@@ -145,7 +153,7 @@ class AntminerModern(BMMiner):
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
async def get_mac(self, web_get_system_info: dict = None) -> Union[str, None]:
|
||||
async def _get_mac(self, web_get_system_info: dict = None) -> Union[str, None]:
|
||||
if not web_get_system_info:
|
||||
try:
|
||||
web_get_system_info = await self.web.get_system_info()
|
||||
@@ -165,7 +173,7 @@ class AntminerModern(BMMiner):
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
async def get_errors(self, web_summary: dict = None) -> List[MinerErrorData]:
|
||||
async def _get_errors(self, web_summary: dict = None) -> List[MinerErrorData]:
|
||||
if not web_summary:
|
||||
try:
|
||||
web_summary = await self.web.summary()
|
||||
@@ -181,11 +189,47 @@ class AntminerModern(BMMiner):
|
||||
errors.append(X19Error(item["msg"]))
|
||||
except KeyError:
|
||||
continue
|
||||
except (KeyError, IndexError):
|
||||
except LookupError:
|
||||
pass
|
||||
return errors
|
||||
|
||||
async def get_fault_light(self, web_get_blink_status: dict = None) -> bool:
|
||||
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:
|
||||
if self.light:
|
||||
return self.light
|
||||
|
||||
@@ -202,7 +246,7 @@ class AntminerModern(BMMiner):
|
||||
pass
|
||||
return self.light
|
||||
|
||||
async def get_expected_hashrate(self, api_stats: dict = None) -> Optional[float]:
|
||||
async def _get_expected_hashrate(self, api_stats: dict = None) -> Optional[float]:
|
||||
if not api_stats:
|
||||
try:
|
||||
api_stats = await self.api.stats()
|
||||
@@ -222,7 +266,7 @@ class AntminerModern(BMMiner):
|
||||
return round(expected_rate / 1000000, 2)
|
||||
else:
|
||||
return round(expected_rate, 2)
|
||||
except (KeyError, IndexError):
|
||||
except LookupError:
|
||||
pass
|
||||
|
||||
async def set_static_ip(
|
||||
@@ -267,7 +311,7 @@ class AntminerModern(BMMiner):
|
||||
protocol=protocol,
|
||||
)
|
||||
|
||||
async def is_mining(self, web_get_conf: dict = None) -> Optional[bool]:
|
||||
async def _is_mining(self, web_get_conf: dict = None) -> Optional[bool]:
|
||||
if not web_get_conf:
|
||||
try:
|
||||
web_get_conf = await self.web.get_miner_conf()
|
||||
@@ -284,7 +328,7 @@ class AntminerModern(BMMiner):
|
||||
except LookupError:
|
||||
pass
|
||||
|
||||
async def get_uptime(self, api_stats: dict = None) -> Optional[int]:
|
||||
async def _get_uptime(self, api_stats: dict = None) -> Optional[int]:
|
||||
if not api_stats:
|
||||
try:
|
||||
api_stats = await self.api.stats()
|
||||
@@ -298,39 +342,48 @@ class AntminerModern(BMMiner):
|
||||
pass
|
||||
|
||||
|
||||
ANTMINER_OLD_DATA_LOC = {
|
||||
"mac": {"cmd": "get_mac", "kwargs": {}},
|
||||
"model": {"cmd": "get_model", "kwargs": {}},
|
||||
"api_ver": {"cmd": "get_api_ver", "kwargs": {"api_version": {"api": "version"}}},
|
||||
"fw_ver": {"cmd": "get_fw_ver", "kwargs": {"api_version": {"api": "version"}}},
|
||||
"hostname": {
|
||||
"cmd": "get_hostname",
|
||||
"kwargs": {"web_get_system_info": {"web": "get_system_info"}},
|
||||
},
|
||||
"hashrate": {"cmd": "get_hashrate", "kwargs": {"api_summary": {"api": "summary"}}},
|
||||
"expected_hashrate": {
|
||||
"cmd": "get_expected_hashrate",
|
||||
"kwargs": {"api_stats": {"api": "stats"}},
|
||||
},
|
||||
"hashboards": {"cmd": "get_hashboards", "kwargs": {"api_stats": {"api": "stats"}}},
|
||||
"env_temp": {"cmd": "get_env_temp", "kwargs": {}},
|
||||
"wattage": {"cmd": "get_wattage", "kwargs": {}},
|
||||
"wattage_limit": {"cmd": "get_wattage_limit", "kwargs": {}},
|
||||
"fans": {"cmd": "get_fans", "kwargs": {"api_stats": {"api": "stats"}}},
|
||||
"fan_psu": {"cmd": "get_fan_psu", "kwargs": {}},
|
||||
"errors": {"cmd": "get_errors", "kwargs": {}},
|
||||
"fault_light": {
|
||||
"cmd": "get_fault_light",
|
||||
"kwargs": {"web_get_blink_status": {"web": "get_blink_status"}},
|
||||
},
|
||||
"pools": {"cmd": "get_pools", "kwargs": {"api_pools": {"api": "pools"}}},
|
||||
"is_mining": {
|
||||
"cmd": "is_mining",
|
||||
"kwargs": {"web_get_conf": {"web": "get_miner_conf"}},
|
||||
},
|
||||
"uptime": {"cmd": "get_uptime", "kwargs": {"api_stats": {"api": "stats"}}},
|
||||
"config": {"cmd": "get_config", "kwargs": {}},
|
||||
}
|
||||
ANTMINER_OLD_DATA_LOC = DataLocations(
|
||||
**{
|
||||
str(DataOptions.MAC): DataFunction("_get_mac"),
|
||||
str(DataOptions.API_VERSION): DataFunction(
|
||||
"_get_api_ver", [RPCAPICommand("api_version", "version")]
|
||||
),
|
||||
str(DataOptions.FW_VERSION): DataFunction(
|
||||
"_get_fw_ver", [RPCAPICommand("api_version", "version")]
|
||||
),
|
||||
str(DataOptions.HOSTNAME): DataFunction(
|
||||
"_get_hostname", [WebAPICommand("web_get_system_info", "get_system_info")]
|
||||
),
|
||||
str(DataOptions.HASHRATE): DataFunction(
|
||||
"_get_hashrate", [RPCAPICommand("api_summary", "summary")]
|
||||
),
|
||||
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
|
||||
"_get_expected_hashrate", [RPCAPICommand("api_stats", "stats")]
|
||||
),
|
||||
str(DataOptions.HASHBOARDS): DataFunction(
|
||||
"_get_hashboards", [RPCAPICommand("api_stats", "stats")]
|
||||
),
|
||||
str(DataOptions.ENVIRONMENT_TEMP): DataFunction("_get_env_temp"),
|
||||
str(DataOptions.WATTAGE): DataFunction("_get_wattage"),
|
||||
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",
|
||||
[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):
|
||||
@@ -353,7 +406,7 @@ class AntminerOld(CGMiner):
|
||||
self.config = config
|
||||
await self.web.set_miner_conf(config.as_am_old(user_suffix=user_suffix))
|
||||
|
||||
async def get_mac(self) -> Union[str, None]:
|
||||
async def _get_mac(self) -> Union[str, None]:
|
||||
try:
|
||||
data = await self.web.get_system_info()
|
||||
if data:
|
||||
@@ -390,7 +443,7 @@ class AntminerOld(CGMiner):
|
||||
return True
|
||||
return False
|
||||
|
||||
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:
|
||||
return self.light
|
||||
|
||||
@@ -407,7 +460,7 @@ class AntminerOld(CGMiner):
|
||||
pass
|
||||
return self.light
|
||||
|
||||
async def get_hostname(self, web_get_system_info: dict = None) -> Optional[str]:
|
||||
async def _get_hostname(self, web_get_system_info: dict = None) -> Optional[str]:
|
||||
if not web_get_system_info:
|
||||
try:
|
||||
web_get_system_info = await self.web.get_system_info()
|
||||
@@ -420,14 +473,14 @@ class AntminerOld(CGMiner):
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
async def get_fans(self, api_stats: dict = None) -> List[Fan]:
|
||||
async def _get_fans(self, api_stats: dict = None) -> List[Fan]:
|
||||
if not api_stats:
|
||||
try:
|
||||
api_stats = await self.api.stats()
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
fans_data = [Fan() for _ in range(self.fan_count)]
|
||||
fans_data = [Fan() for _ in range(self.expected_fans)]
|
||||
if api_stats:
|
||||
try:
|
||||
fan_offset = -1
|
||||
@@ -440,15 +493,15 @@ class AntminerOld(CGMiner):
|
||||
if fan_offset == -1:
|
||||
fan_offset = 3
|
||||
|
||||
for fan in range(self.fan_count):
|
||||
for fan in range(self.expected_fans):
|
||||
fans_data[fan].speed = api_stats["STATS"][1].get(
|
||||
f"fan{fan_offset+fan}", 0
|
||||
)
|
||||
except (KeyError, IndexError):
|
||||
except LookupError:
|
||||
pass
|
||||
return fans_data
|
||||
|
||||
async def get_hashboards(self, api_stats: dict = None) -> List[HashBoard]:
|
||||
async def _get_hashboards(self, api_stats: dict = None) -> List[HashBoard]:
|
||||
hashboards = []
|
||||
|
||||
if not api_stats:
|
||||
@@ -497,12 +550,12 @@ class AntminerOld(CGMiner):
|
||||
if (not chips) or (not chips > 0):
|
||||
hashboard.missing = True
|
||||
hashboards.append(hashboard)
|
||||
except (IndexError, KeyError, ValueError, TypeError):
|
||||
except (LookupError, ValueError, TypeError):
|
||||
pass
|
||||
|
||||
return hashboards
|
||||
|
||||
async def is_mining(self, web_get_conf: dict = None) -> Optional[bool]:
|
||||
async def _is_mining(self, web_get_conf: dict = None) -> Optional[bool]:
|
||||
if not web_get_conf:
|
||||
try:
|
||||
web_get_conf = await self.web.get_miner_conf()
|
||||
@@ -527,7 +580,7 @@ class AntminerOld(CGMiner):
|
||||
else:
|
||||
return False
|
||||
|
||||
async def get_uptime(self, api_stats: dict = None) -> Optional[int]:
|
||||
async def _get_uptime(self, api_stats: dict = None) -> Optional[int]:
|
||||
if not api_stats:
|
||||
try:
|
||||
api_stats = await self.api.stats()
|
||||
|
||||
@@ -14,40 +14,54 @@
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
from collections import namedtuple
|
||||
from typing import List, Optional, Tuple
|
||||
from typing import List, Optional
|
||||
|
||||
from pyasic.API.bfgminer import BFGMinerAPI
|
||||
from pyasic.config import MinerConfig
|
||||
from pyasic.data import Fan, HashBoard
|
||||
from pyasic.data.error_codes import MinerErrorData
|
||||
from pyasic.errors import APIError
|
||||
from pyasic.miners.base import BaseMiner
|
||||
from pyasic.miners.base import (
|
||||
BaseMiner,
|
||||
DataFunction,
|
||||
DataLocations,
|
||||
DataOptions,
|
||||
RPCAPICommand,
|
||||
)
|
||||
|
||||
BFGMINER_DATA_LOC = {
|
||||
"mac": {"cmd": "get_mac", "kwargs": {}},
|
||||
"model": {"cmd": "get_model", "kwargs": {}},
|
||||
"api_ver": {"cmd": "get_api_ver", "kwargs": {"api_version": {"api": "version"}}},
|
||||
"fw_ver": {"cmd": "get_fw_ver", "kwargs": {"api_version": {"api": "version"}}},
|
||||
"hostname": {"cmd": "get_hostname", "kwargs": {}},
|
||||
"hashrate": {"cmd": "get_hashrate", "kwargs": {"api_summary": {"api": "summary"}}},
|
||||
"expected_hashrate": {
|
||||
"cmd": "get_expected_hashrate",
|
||||
"kwargs": {"api_stats": {"api": "stats"}},
|
||||
},
|
||||
"hashboards": {"cmd": "get_hashboards", "kwargs": {"api_stats": {"api": "stats"}}},
|
||||
"env_temp": {"cmd": "get_env_temp", "kwargs": {}},
|
||||
"wattage": {"cmd": "get_wattage", "kwargs": {}},
|
||||
"wattage_limit": {"cmd": "get_wattage_limit", "kwargs": {}},
|
||||
"fans": {"cmd": "get_fans", "kwargs": {"api_stats": {"api": "stats"}}},
|
||||
"fan_psu": {"cmd": "get_fan_psu", "kwargs": {}},
|
||||
"errors": {"cmd": "get_errors", "kwargs": {}},
|
||||
"fault_light": {"cmd": "get_fault_light", "kwargs": {}},
|
||||
"pools": {"cmd": "get_pools", "kwargs": {"api_pools": {"api": "pools"}}},
|
||||
"is_mining": {"cmd": "is_mining", "kwargs": {}},
|
||||
"uptime": {"cmd": "get_uptime", "kwargs": {}},
|
||||
"config": {"cmd": "get_config", "kwargs": {}},
|
||||
}
|
||||
BFGMINER_DATA_LOC = DataLocations(
|
||||
**{
|
||||
str(DataOptions.MAC): DataFunction("_get_mac"),
|
||||
str(DataOptions.API_VERSION): DataFunction(
|
||||
"_get_api_ver", [RPCAPICommand("api_version", "version")]
|
||||
),
|
||||
str(DataOptions.FW_VERSION): DataFunction(
|
||||
"_get_fw_ver", [RPCAPICommand("api_version", "version")]
|
||||
),
|
||||
str(DataOptions.HOSTNAME): DataFunction("_get_hostname"),
|
||||
str(DataOptions.HASHRATE): DataFunction(
|
||||
"_get_hashrate", [RPCAPICommand("api_summary", "summary")]
|
||||
),
|
||||
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
|
||||
"_get_expected_hashrate", [RPCAPICommand("api_stats", "stats")]
|
||||
),
|
||||
str(DataOptions.HASHBOARDS): DataFunction(
|
||||
"_get_hashboards", [RPCAPICommand("api_stats", "stats")]
|
||||
),
|
||||
str(DataOptions.ENVIRONMENT_TEMP): DataFunction("_get_env_temp"),
|
||||
str(DataOptions.WATTAGE): DataFunction("_get_wattage"),
|
||||
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):
|
||||
@@ -101,14 +115,10 @@ class BFGMiner(BaseMiner):
|
||||
### DATA GATHERING FUNCTIONS (get_{some_data}) ###
|
||||
##################################################
|
||||
|
||||
async def get_mac(self) -> str:
|
||||
return "00:00:00:00:00:00"
|
||||
|
||||
async def get_api_ver(self, api_version: dict = None) -> Optional[str]:
|
||||
# Check to see if the version info is already cached
|
||||
if self.api_ver:
|
||||
return self.api_ver
|
||||
async def _get_mac(self) -> Optional[str]:
|
||||
return None
|
||||
|
||||
async def _get_api_ver(self, api_version: dict = None) -> Optional[str]:
|
||||
if not api_version:
|
||||
try:
|
||||
api_version = await self.api.version()
|
||||
@@ -118,16 +128,12 @@ class BFGMiner(BaseMiner):
|
||||
if api_version:
|
||||
try:
|
||||
self.api_ver = api_version["VERSION"][0]["API"]
|
||||
except (KeyError, IndexError):
|
||||
except LookupError:
|
||||
pass
|
||||
|
||||
return self.api_ver
|
||||
|
||||
async def get_fw_ver(self, api_version: dict = None) -> Optional[str]:
|
||||
# Check to see if the version info is already cached
|
||||
if self.fw_ver:
|
||||
return self.fw_ver
|
||||
|
||||
async def _get_fw_ver(self, api_version: dict = None) -> Optional[str]:
|
||||
if not api_version:
|
||||
try:
|
||||
api_version = await self.api.version()
|
||||
@@ -137,31 +143,21 @@ class BFGMiner(BaseMiner):
|
||||
if api_version:
|
||||
try:
|
||||
self.fw_ver = api_version["VERSION"][0]["CompileTime"]
|
||||
except (KeyError, IndexError):
|
||||
except LookupError:
|
||||
pass
|
||||
|
||||
return self.fw_ver
|
||||
|
||||
async def get_version(
|
||||
self, api_version: dict = None
|
||||
) -> Tuple[Optional[str], Optional[str]]:
|
||||
# check if version is cached
|
||||
miner_version = namedtuple("MinerVersion", "api_ver fw_ver")
|
||||
return miner_version(
|
||||
api_ver=await self.get_api_ver(api_version),
|
||||
fw_ver=await self.get_fw_ver(api_version=api_version),
|
||||
)
|
||||
|
||||
async def reboot(self) -> bool:
|
||||
return False
|
||||
|
||||
async def get_fan_psu(self):
|
||||
async def _get_fan_psu(self):
|
||||
return None
|
||||
|
||||
async def get_hostname(self) -> Optional[str]:
|
||||
async def _get_hostname(self) -> Optional[str]:
|
||||
return None
|
||||
|
||||
async def get_hashrate(self, api_summary: dict = None) -> Optional[float]:
|
||||
async def _get_hashrate(self, api_summary: dict = None) -> Optional[float]:
|
||||
# get hr from API
|
||||
if not api_summary:
|
||||
try:
|
||||
@@ -172,10 +168,10 @@ class BFGMiner(BaseMiner):
|
||||
if api_summary:
|
||||
try:
|
||||
return round(float(api_summary["SUMMARY"][0]["MHS 20s"] / 1000000), 2)
|
||||
except (IndexError, KeyError, ValueError, TypeError):
|
||||
except (LookupError, ValueError, TypeError):
|
||||
pass
|
||||
|
||||
async def get_hashboards(self, api_stats: dict = None) -> List[HashBoard]:
|
||||
async def _get_hashboards(self, api_stats: dict = None) -> List[HashBoard]:
|
||||
hashboards = []
|
||||
|
||||
if not api_stats:
|
||||
@@ -224,21 +220,21 @@ class BFGMiner(BaseMiner):
|
||||
if (not chips) or (not chips > 0):
|
||||
hashboard.missing = True
|
||||
hashboards.append(hashboard)
|
||||
except (IndexError, KeyError, ValueError, TypeError):
|
||||
except (LookupError, ValueError, TypeError):
|
||||
pass
|
||||
|
||||
return hashboards
|
||||
|
||||
async def get_env_temp(self) -> Optional[float]:
|
||||
async def _get_env_temp(self) -> Optional[float]:
|
||||
return None
|
||||
|
||||
async def get_wattage(self) -> Optional[int]:
|
||||
async def _get_wattage(self) -> Optional[int]:
|
||||
return None
|
||||
|
||||
async def get_wattage_limit(self) -> Optional[int]:
|
||||
async def _get_wattage_limit(self) -> Optional[int]:
|
||||
return None
|
||||
|
||||
async def get_fans(self, api_stats: dict = None) -> List[Fan]:
|
||||
async def _get_fans(self, api_stats: dict = None) -> List[Fan]:
|
||||
if not api_stats:
|
||||
try:
|
||||
api_stats = await self.api.stats()
|
||||
@@ -258,49 +254,23 @@ class BFGMiner(BaseMiner):
|
||||
if fan_offset == -1:
|
||||
fan_offset = 1
|
||||
|
||||
for fan in range(self.fan_count):
|
||||
for fan in range(self.expected_fans):
|
||||
fans_data[fan] = api_stats["STATS"][1].get(
|
||||
f"fan{fan_offset+fan}", 0
|
||||
)
|
||||
except (KeyError, IndexError):
|
||||
except LookupError:
|
||||
pass
|
||||
fans = [Fan(speed=d) if d else Fan() for d in fans_data]
|
||||
|
||||
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 []
|
||||
|
||||
async def get_fault_light(self) -> bool:
|
||||
async def _get_fault_light(self) -> bool:
|
||||
return False
|
||||
|
||||
async def get_expected_hashrate(self, api_stats: dict = None) -> Optional[float]:
|
||||
async def _get_expected_hashrate(self, api_stats: dict = None) -> Optional[float]:
|
||||
# X19 method, not sure compatibility
|
||||
if not api_stats:
|
||||
try:
|
||||
@@ -321,11 +291,11 @@ class BFGMiner(BaseMiner):
|
||||
return round(expected_rate / 1000000, 2)
|
||||
else:
|
||||
return round(expected_rate, 2)
|
||||
except (KeyError, IndexError):
|
||||
except LookupError:
|
||||
pass
|
||||
|
||||
async def is_mining(self, *args, **kwargs) -> Optional[bool]:
|
||||
async def _is_mining(self, *args, **kwargs) -> Optional[bool]:
|
||||
return None
|
||||
|
||||
async def get_uptime(self, *args, **kwargs) -> Optional[int]:
|
||||
async def _get_uptime(self, *args, **kwargs) -> Optional[int]:
|
||||
return None
|
||||
|
||||
@@ -20,41 +20,54 @@ from pyasic.data import HashBoard
|
||||
from pyasic.errors import APIError
|
||||
from pyasic.logger import logger
|
||||
from pyasic.miners.backends import BFGMiner
|
||||
from pyasic.miners.base import (
|
||||
DataFunction,
|
||||
DataLocations,
|
||||
DataOptions,
|
||||
RPCAPICommand,
|
||||
WebAPICommand,
|
||||
)
|
||||
from pyasic.web.goldshell import GoldshellWebAPI
|
||||
|
||||
GOLDSHELL_DATA_LOC = {
|
||||
"mac": {"cmd": "get_mac", "kwargs": {"web_setting": {"web": "setting"}}},
|
||||
"model": {"cmd": "get_model", "kwargs": {}},
|
||||
"api_ver": {"cmd": "get_api_ver", "kwargs": {"api_version": {"api": "version"}}},
|
||||
"fw_ver": {"cmd": "get_fw_ver", "kwargs": {"web_status": {"web": "status"}}},
|
||||
"hostname": {"cmd": "get_hostname", "kwargs": {}},
|
||||
"hashrate": {"cmd": "get_hashrate", "kwargs": {"api_summary": {"api": "summary"}}},
|
||||
"expected_hashrate": {
|
||||
"cmd": "get_expected_hashrate",
|
||||
"kwargs": {"api_stats": {"api": "stats"}},
|
||||
},
|
||||
"hashboards": {
|
||||
"cmd": "get_hashboards",
|
||||
"kwargs": {
|
||||
"api_devs": {"api": "devs"},
|
||||
"api_devdetails": {"api": "devdetails"},
|
||||
},
|
||||
},
|
||||
"env_temp": {"cmd": "get_env_temp", "kwargs": {}},
|
||||
"wattage": {"cmd": "get_wattage", "kwargs": {}},
|
||||
"wattage_limit": {"cmd": "get_wattage_limit", "kwargs": {}},
|
||||
"fans": {"cmd": "get_fans", "kwargs": {"api_stats": {"api": "stats"}}},
|
||||
"fan_psu": {"cmd": "get_fan_psu", "kwargs": {}},
|
||||
"errors": {"cmd": "get_errors", "kwargs": {}},
|
||||
"fault_light": {"cmd": "get_fault_light", "kwargs": {}},
|
||||
"pools": {"cmd": "get_pools", "kwargs": {"api_pools": {"api": "pools"}}},
|
||||
"is_mining": {"cmd": "is_mining", "kwargs": {}},
|
||||
"uptime": {"cmd": "get_uptime", "kwargs": {}},
|
||||
"config": {
|
||||
"cmd": "get_config",
|
||||
"kwargs": {},
|
||||
},
|
||||
}
|
||||
GOLDSHELL_DATA_LOC = DataLocations(
|
||||
**{
|
||||
str(DataOptions.MAC): DataFunction(
|
||||
"_get_mac", [WebAPICommand("web_setting", "setting")]
|
||||
),
|
||||
str(DataOptions.API_VERSION): DataFunction(
|
||||
"_get_api_ver", [RPCAPICommand("api_version", "version")]
|
||||
),
|
||||
str(DataOptions.FW_VERSION): DataFunction(
|
||||
"_get_fw_ver", [WebAPICommand("web_status", "status")]
|
||||
),
|
||||
str(DataOptions.HOSTNAME): DataFunction("_get_hostname"),
|
||||
str(DataOptions.HASHRATE): DataFunction(
|
||||
"_get_hashrate", [RPCAPICommand("api_summary", "summary")]
|
||||
),
|
||||
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
|
||||
"_get_expected_hashrate", [RPCAPICommand("api_stats", "stats")]
|
||||
),
|
||||
str(DataOptions.HASHBOARDS): DataFunction(
|
||||
"_get_hashboards",
|
||||
[
|
||||
RPCAPICommand("api_devs", "devs"),
|
||||
RPCAPICommand("api_devdetails", "devdetails"),
|
||||
],
|
||||
),
|
||||
str(DataOptions.ENVIRONMENT_TEMP): DataFunction("_get_env_temp"),
|
||||
str(DataOptions.WATTAGE): DataFunction("_get_wattage"),
|
||||
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 BFGMinerGoldshell(BFGMiner):
|
||||
@@ -96,7 +109,7 @@ class BFGMinerGoldshell(BFGMiner):
|
||||
url=pool["url"], user=pool["user"], password=pool["pass"]
|
||||
)
|
||||
|
||||
async def get_mac(self, web_setting: dict = None) -> str:
|
||||
async def _get_mac(self, web_setting: dict = None) -> str:
|
||||
if not web_setting:
|
||||
try:
|
||||
web_setting = await self.web.setting()
|
||||
@@ -109,7 +122,7 @@ class BFGMinerGoldshell(BFGMiner):
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
async def get_fw_ver(self, web_status: dict = None) -> str:
|
||||
async def _get_fw_ver(self, web_status: dict = None) -> str:
|
||||
if not web_status:
|
||||
try:
|
||||
web_status = await self.web.setting()
|
||||
@@ -122,7 +135,7 @@ class BFGMinerGoldshell(BFGMiner):
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
async def get_hashboards(
|
||||
async def _get_hashboards(
|
||||
self, api_devs: dict = None, api_devdetails: dict = None
|
||||
) -> List[HashBoard]:
|
||||
if not api_devs:
|
||||
@@ -172,8 +185,8 @@ class BFGMinerGoldshell(BFGMiner):
|
||||
|
||||
return hashboards
|
||||
|
||||
async def is_mining(self, *args, **kwargs) -> Optional[bool]:
|
||||
async def _is_mining(self, *args, **kwargs) -> Optional[bool]:
|
||||
return None
|
||||
|
||||
async def get_uptime(self, *args, **kwargs) -> Optional[int]:
|
||||
async def _get_uptime(self, *args, **kwargs) -> Optional[int]:
|
||||
return None
|
||||
|
||||
@@ -15,40 +15,56 @@
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
import logging
|
||||
from collections import namedtuple
|
||||
from typing import List, Optional, Tuple
|
||||
from typing import List, Optional
|
||||
|
||||
from pyasic.API.bmminer import BMMinerAPI
|
||||
from pyasic.config import MinerConfig
|
||||
from pyasic.data import Fan, HashBoard
|
||||
from pyasic.data.error_codes import MinerErrorData
|
||||
from pyasic.errors import APIError
|
||||
from pyasic.miners.base import BaseMiner
|
||||
from pyasic.miners.base import (
|
||||
BaseMiner,
|
||||
DataFunction,
|
||||
DataLocations,
|
||||
DataOptions,
|
||||
RPCAPICommand,
|
||||
)
|
||||
|
||||
BMMINER_DATA_LOC = {
|
||||
"mac": {"cmd": "get_mac", "kwargs": {}},
|
||||
"model": {"cmd": "get_model", "kwargs": {}},
|
||||
"api_ver": {"cmd": "get_api_ver", "kwargs": {"api_version": {"api": "version"}}},
|
||||
"fw_ver": {"cmd": "get_fw_ver", "kwargs": {"api_version": {"api": "version"}}},
|
||||
"hostname": {"cmd": "get_hostname", "kwargs": {}},
|
||||
"hashrate": {"cmd": "get_hashrate", "kwargs": {"api_summary": {"api": "summary"}}},
|
||||
"expected_hashrate": {
|
||||
"cmd": "get_expected_hashrate",
|
||||
"kwargs": {"api_stats": {"api": "stats"}},
|
||||
},
|
||||
"hashboards": {"cmd": "get_hashboards", "kwargs": {"api_stats": {"api": "stats"}}},
|
||||
"env_temp": {"cmd": "get_env_temp", "kwargs": {}},
|
||||
"wattage": {"cmd": "get_wattage", "kwargs": {}},
|
||||
"wattage_limit": {"cmd": "get_wattage_limit", "kwargs": {}},
|
||||
"fans": {"cmd": "get_fans", "kwargs": {"api_stats": {"api": "stats"}}},
|
||||
"fan_psu": {"cmd": "get_fan_psu", "kwargs": {}},
|
||||
"errors": {"cmd": "get_errors", "kwargs": {}},
|
||||
"fault_light": {"cmd": "get_fault_light", "kwargs": {}},
|
||||
"pools": {"cmd": "get_pools", "kwargs": {"api_pools": {"api": "pools"}}},
|
||||
"is_mining": {"cmd": "is_mining", "kwargs": {}},
|
||||
"uptime": {"cmd": "get_uptime", "kwargs": {"api_stats": {"api": "stats"}}},
|
||||
"config": {"cmd": "get_config", "kwargs": {}},
|
||||
}
|
||||
BMMINER_DATA_LOC = DataLocations(
|
||||
**{
|
||||
str(DataOptions.MAC): DataFunction("_get_mac"),
|
||||
str(DataOptions.API_VERSION): DataFunction(
|
||||
"_get_api_ver", [RPCAPICommand("api_version", "version")]
|
||||
),
|
||||
str(DataOptions.FW_VERSION): DataFunction(
|
||||
"_get_fw_ver", [RPCAPICommand("api_version", "version")]
|
||||
),
|
||||
str(DataOptions.HOSTNAME): DataFunction("_get_hostname"),
|
||||
str(DataOptions.HASHRATE): DataFunction(
|
||||
"_get_hashrate", [RPCAPICommand("api_summary", "summary")]
|
||||
),
|
||||
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
|
||||
"_get_expected_hashrate", [RPCAPICommand("api_stats", "stats")]
|
||||
),
|
||||
str(DataOptions.HASHBOARDS): DataFunction(
|
||||
"_get_hashboards", [RPCAPICommand("api_stats", "stats")]
|
||||
),
|
||||
str(DataOptions.ENVIRONMENT_TEMP): DataFunction("_get_env_temp"),
|
||||
str(DataOptions.WATTAGE): DataFunction("_get_wattage"),
|
||||
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):
|
||||
@@ -138,14 +154,10 @@ class BMMiner(BaseMiner):
|
||||
### DATA GATHERING FUNCTIONS (get_{some_data}) ###
|
||||
##################################################
|
||||
|
||||
async def get_mac(self) -> str:
|
||||
return "00:00:00:00:00:00"
|
||||
|
||||
async def get_api_ver(self, api_version: dict = None) -> Optional[str]:
|
||||
# Check to see if the version info is already cached
|
||||
if self.api_ver:
|
||||
return self.api_ver
|
||||
async def _get_mac(self) -> Optional[str]:
|
||||
return None
|
||||
|
||||
async def _get_api_ver(self, api_version: dict = None) -> Optional[str]:
|
||||
if not api_version:
|
||||
try:
|
||||
api_version = await self.api.version()
|
||||
@@ -155,16 +167,12 @@ class BMMiner(BaseMiner):
|
||||
if api_version:
|
||||
try:
|
||||
self.api_ver = api_version["VERSION"][0]["API"]
|
||||
except (KeyError, IndexError):
|
||||
except LookupError:
|
||||
pass
|
||||
|
||||
return self.api_ver
|
||||
|
||||
async def get_fw_ver(self, api_version: dict = None) -> Optional[str]:
|
||||
# Check to see if the version info is already cached
|
||||
if self.fw_ver:
|
||||
return self.fw_ver
|
||||
|
||||
async def _get_fw_ver(self, api_version: dict = None) -> Optional[str]:
|
||||
if not api_version:
|
||||
try:
|
||||
api_version = await self.api.version()
|
||||
@@ -174,29 +182,19 @@ class BMMiner(BaseMiner):
|
||||
if api_version:
|
||||
try:
|
||||
self.fw_ver = api_version["VERSION"][0]["CompileTime"]
|
||||
except (KeyError, IndexError):
|
||||
except LookupError:
|
||||
pass
|
||||
|
||||
return self.fw_ver
|
||||
|
||||
async def get_version(
|
||||
self, api_version: dict = None
|
||||
) -> Tuple[Optional[str], Optional[str]]:
|
||||
# check if version is cached
|
||||
miner_version = namedtuple("MinerVersion", "api_ver fw_ver")
|
||||
return miner_version(
|
||||
api_ver=await self.get_api_ver(api_version),
|
||||
fw_ver=await self.get_fw_ver(api_version=api_version),
|
||||
)
|
||||
|
||||
async def get_fan_psu(self):
|
||||
async def _get_fan_psu(self):
|
||||
return None
|
||||
|
||||
async def get_hostname(self) -> Optional[str]:
|
||||
async def _get_hostname(self) -> Optional[str]:
|
||||
hn = await self.send_ssh_command("cat /proc/sys/kernel/hostname")
|
||||
return hn
|
||||
|
||||
async def get_hashrate(self, api_summary: dict = None) -> Optional[float]:
|
||||
async def _get_hashrate(self, api_summary: dict = None) -> Optional[float]:
|
||||
# get hr from API
|
||||
if not api_summary:
|
||||
try:
|
||||
@@ -207,10 +205,10 @@ class BMMiner(BaseMiner):
|
||||
if api_summary:
|
||||
try:
|
||||
return round(float(api_summary["SUMMARY"][0]["GHS 5s"] / 1000), 2)
|
||||
except (IndexError, KeyError, ValueError, TypeError):
|
||||
except (LookupError, ValueError, TypeError):
|
||||
pass
|
||||
|
||||
async def get_hashboards(self, api_stats: dict = None) -> List[HashBoard]:
|
||||
async def _get_hashboards(self, api_stats: dict = None) -> List[HashBoard]:
|
||||
hashboards = []
|
||||
|
||||
if not api_stats:
|
||||
@@ -277,23 +275,23 @@ class BMMiner(BaseMiner):
|
||||
|
||||
return hashboards
|
||||
|
||||
async def get_env_temp(self) -> Optional[float]:
|
||||
async def _get_env_temp(self) -> Optional[float]:
|
||||
return None
|
||||
|
||||
async def get_wattage(self) -> Optional[int]:
|
||||
async def _get_wattage(self) -> Optional[int]:
|
||||
return None
|
||||
|
||||
async def get_wattage_limit(self) -> Optional[int]:
|
||||
async def _get_wattage_limit(self) -> Optional[int]:
|
||||
return None
|
||||
|
||||
async def get_fans(self, api_stats: dict = None) -> List[Fan]:
|
||||
async def _get_fans(self, api_stats: dict = None) -> List[Fan]:
|
||||
if not api_stats:
|
||||
try:
|
||||
api_stats = await self.api.stats()
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
fans = [Fan() for _ in range(self.fan_count)]
|
||||
fans = [Fan() for _ in range(self.expected_fans)]
|
||||
if api_stats:
|
||||
try:
|
||||
fan_offset = -1
|
||||
@@ -306,48 +304,22 @@ class BMMiner(BaseMiner):
|
||||
if fan_offset == -1:
|
||||
fan_offset = 1
|
||||
|
||||
for fan in range(self.fan_count):
|
||||
for fan in range(self.expected_fans):
|
||||
fans[fan].speed = api_stats["STATS"][1].get(
|
||||
f"fan{fan_offset+fan}", 0
|
||||
)
|
||||
except (KeyError, IndexError):
|
||||
except LookupError:
|
||||
pass
|
||||
|
||||
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 []
|
||||
|
||||
async def get_fault_light(self) -> bool:
|
||||
async def _get_fault_light(self) -> bool:
|
||||
return False
|
||||
|
||||
async def get_expected_hashrate(self, api_stats: dict = None) -> Optional[float]:
|
||||
async def _get_expected_hashrate(self, api_stats: dict = None) -> Optional[float]:
|
||||
# X19 method, not sure compatibility
|
||||
if not api_stats:
|
||||
try:
|
||||
@@ -368,16 +340,16 @@ class BMMiner(BaseMiner):
|
||||
return round(expected_rate / 1000000, 2)
|
||||
else:
|
||||
return round(expected_rate, 2)
|
||||
except (KeyError, IndexError):
|
||||
except LookupError:
|
||||
pass
|
||||
|
||||
async def is_mining(self, *args, **kwargs) -> Optional[bool]:
|
||||
async def _is_mining(self, *args, **kwargs) -> Optional[bool]:
|
||||
return None
|
||||
|
||||
async def get_uptime(self, api_stats: dict = None) -> Optional[int]:
|
||||
async def _get_uptime(self, api_stats: dict = None) -> Optional[int]:
|
||||
if not api_stats:
|
||||
try:
|
||||
api_stats = await self.web.get_miner_conf()
|
||||
api_stats = await self.api.stats()
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,158 +0,0 @@
|
||||
# ------------------------------------------------------------------------------
|
||||
# Copyright 2022 Upstream Data Inc -
|
||||
# -
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); -
|
||||
# you may not use this file except in compliance with the License. -
|
||||
# You may obtain a copy of the License at -
|
||||
# -
|
||||
# http://www.apache.org/licenses/LICENSE-2.0 -
|
||||
# -
|
||||
# Unless required by applicable law or agreed to in writing, software -
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, -
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -
|
||||
# See the License for the specific language governing permissions and -
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
import logging
|
||||
from typing import List, Optional, Tuple
|
||||
|
||||
from pyasic.config import MinerConfig
|
||||
from pyasic.data import Fan, HashBoard, MinerData
|
||||
from pyasic.data.error_codes import MinerErrorData
|
||||
from pyasic.miners.backends import BOSMiner
|
||||
|
||||
|
||||
class BOSMinerOld(BOSMiner):
|
||||
def __init__(self, ip: str, api_ver: str = "0.0.0") -> None:
|
||||
super().__init__(ip, api_ver)
|
||||
|
||||
async def send_ssh_command(self, cmd: str) -> Optional[str]:
|
||||
result = None
|
||||
|
||||
try:
|
||||
conn = await self._get_ssh_connection()
|
||||
except ConnectionError:
|
||||
return None
|
||||
|
||||
# open an ssh connection
|
||||
async with conn:
|
||||
# 3 retries
|
||||
for i in range(3):
|
||||
try:
|
||||
# run the command and get the result
|
||||
result = await conn.run(cmd)
|
||||
result = result.stdout
|
||||
|
||||
except Exception as e:
|
||||
# if the command fails, log it
|
||||
logging.warning(f"{self} command {cmd} error: {e}")
|
||||
|
||||
# on the 3rd retry, return None
|
||||
if i == 3:
|
||||
return
|
||||
continue
|
||||
# return the result, either command output or None
|
||||
return result
|
||||
|
||||
async def update_to_plus(self):
|
||||
result = await self.send_ssh_command("opkg update && opkg install bos_plus")
|
||||
return result
|
||||
|
||||
async def check_light(self) -> bool:
|
||||
return False
|
||||
|
||||
async def fault_light_on(self) -> bool:
|
||||
return False
|
||||
|
||||
async def fault_light_off(self) -> bool:
|
||||
return False
|
||||
|
||||
async def get_config(self) -> None:
|
||||
return None
|
||||
|
||||
async def reboot(self) -> bool:
|
||||
return False
|
||||
|
||||
async def restart_backend(self) -> bool:
|
||||
return False
|
||||
|
||||
async def stop_mining(self) -> bool:
|
||||
return False
|
||||
|
||||
async def resume_mining(self) -> bool:
|
||||
return False
|
||||
|
||||
async def send_config(self, config: MinerConfig, user_suffix: str = None) -> None:
|
||||
return None
|
||||
|
||||
async def set_power_limit(self, wattage: int) -> bool:
|
||||
return False
|
||||
|
||||
##################################################
|
||||
### DATA GATHERING FUNCTIONS (get_{some_data}) ###
|
||||
##################################################
|
||||
|
||||
async def get_mac(self, *args, **kwargs) -> Optional[str]:
|
||||
return None
|
||||
|
||||
async def get_model(self, *args, **kwargs) -> str:
|
||||
return "S9"
|
||||
|
||||
async def get_version(self, *args, **kwargs) -> Tuple[Optional[str], Optional[str]]:
|
||||
return None, None
|
||||
|
||||
async def get_hostname(self, *args, **kwargs) -> Optional[str]:
|
||||
return None
|
||||
|
||||
async def get_hashrate(self, *args, **kwargs) -> Optional[float]:
|
||||
return None
|
||||
|
||||
async def get_hashboards(self, *args, **kwargs) -> List[HashBoard]:
|
||||
return []
|
||||
|
||||
async def get_env_temp(self, *args, **kwargs) -> Optional[float]:
|
||||
return None
|
||||
|
||||
async def get_wattage(self, *args, **kwargs) -> Optional[int]:
|
||||
return None
|
||||
|
||||
async def get_wattage_limit(self, *args, **kwargs) -> Optional[int]:
|
||||
return None
|
||||
|
||||
async def get_fans(
|
||||
self,
|
||||
*args,
|
||||
**kwargs,
|
||||
) -> List[Fan]:
|
||||
return [Fan(), Fan(), Fan(), Fan()]
|
||||
|
||||
async def get_fan_psu(self, *args, **kwargs) -> Optional[int]:
|
||||
return None
|
||||
|
||||
async def get_api_ver(self, *args, **kwargs) -> Optional[str]:
|
||||
return None
|
||||
|
||||
async def get_fw_ver(self, *args, **kwargs) -> Optional[str]:
|
||||
return None
|
||||
|
||||
async def get_pools(self, *args, **kwargs) -> List[dict]:
|
||||
return []
|
||||
|
||||
async def get_errors(self, *args, **kwargs) -> List[MinerErrorData]:
|
||||
return []
|
||||
|
||||
async def get_fault_light(self, *args, **kwargs) -> bool:
|
||||
return False
|
||||
|
||||
async def get_expected_hashrate(self, *args, **kwargs) -> Optional[float]:
|
||||
return None
|
||||
|
||||
async def get_data(self, allow_warning: bool = False, **kwargs) -> MinerData:
|
||||
return MinerData(ip=str(self.ip))
|
||||
|
||||
async def is_mining(self, *args, **kwargs) -> Optional[bool]:
|
||||
return None
|
||||
|
||||
async def get_uptime(self, *args, **kwargs) -> Optional[int]:
|
||||
return None
|
||||
1066
pyasic/miners/backends/braiins_os.py
Normal file
1066
pyasic/miners/backends/braiins_os.py
Normal file
File diff suppressed because it is too large
Load Diff
@@ -15,82 +15,95 @@
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
import logging
|
||||
from collections import namedtuple
|
||||
from typing import List, Optional, Tuple
|
||||
from typing import List, Optional
|
||||
|
||||
from pyasic.API.btminer import BTMinerAPI
|
||||
from pyasic.config import MinerConfig, MiningModeConfig
|
||||
from pyasic.data import Fan, HashBoard
|
||||
from pyasic.data.error_codes import MinerErrorData, WhatsminerError
|
||||
from pyasic.errors import APIError
|
||||
from pyasic.miners.base import BaseMiner
|
||||
from pyasic.miners.base import (
|
||||
BaseMiner,
|
||||
DataFunction,
|
||||
DataLocations,
|
||||
DataOptions,
|
||||
RPCAPICommand,
|
||||
)
|
||||
|
||||
BTMINER_DATA_LOC = {
|
||||
"mac": {
|
||||
"cmd": "get_mac",
|
||||
"kwargs": {
|
||||
"api_summary": {"api": "summary"},
|
||||
"api_get_miner_info": {"api": "get_miner_info"},
|
||||
},
|
||||
},
|
||||
"model": {"cmd": "get_model", "kwargs": {}},
|
||||
"api_ver": {
|
||||
"cmd": "get_api_ver",
|
||||
"kwargs": {"api_get_version": {"api": "get_version"}},
|
||||
},
|
||||
"fw_ver": {
|
||||
"cmd": "get_fw_ver",
|
||||
"kwargs": {
|
||||
"api_get_version": {"api": "get_version"},
|
||||
"api_summary": {"api": "summary"},
|
||||
},
|
||||
},
|
||||
"hostname": {
|
||||
"cmd": "get_hostname",
|
||||
"kwargs": {"api_get_miner_info": {"api": "get_miner_info"}},
|
||||
},
|
||||
"hashrate": {"cmd": "get_hashrate", "kwargs": {"api_summary": {"api": "summary"}}},
|
||||
"expected_hashrate": {
|
||||
"cmd": "get_expected_hashrate",
|
||||
"kwargs": {"api_summary": {"api": "summary"}},
|
||||
},
|
||||
"hashboards": {"cmd": "get_hashboards", "kwargs": {"api_devs": {"api": "devs"}}},
|
||||
"env_temp": {"cmd": "get_env_temp", "kwargs": {"api_summary": {"api": "summary"}}},
|
||||
"wattage": {"cmd": "get_wattage", "kwargs": {"api_summary": {"api": "summary"}}},
|
||||
"wattage_limit": {
|
||||
"cmd": "get_wattage_limit",
|
||||
"kwargs": {"api_summary": {"api": "summary"}},
|
||||
},
|
||||
"fans": {
|
||||
"cmd": "get_fans",
|
||||
"kwargs": {
|
||||
"api_summary": {"api": "summary"},
|
||||
"api_get_psu": {"api": "get_psu"},
|
||||
},
|
||||
},
|
||||
"fan_psu": {
|
||||
"cmd": "get_fan_psu",
|
||||
"kwargs": {
|
||||
"api_summary": {"api": "summary"},
|
||||
"api_get_psu": {"api": "get_psu"},
|
||||
},
|
||||
},
|
||||
"errors": {
|
||||
"cmd": "get_errors",
|
||||
"kwargs": {
|
||||
"api_summary": {"api": "summary"},
|
||||
"api_get_error_code": {"api": "get_error_code"},
|
||||
},
|
||||
},
|
||||
"fault_light": {
|
||||
"cmd": "get_fault_light",
|
||||
"kwargs": {"api_get_miner_info": {"api": "get_miner_info"}},
|
||||
},
|
||||
"pools": {"cmd": "get_pools", "kwargs": {"api_pools": {"api": "pools"}}},
|
||||
"is_mining": {"cmd": "is_mining", "kwargs": {"api_status": {"api": "status"}}},
|
||||
"uptime": {"cmd": "get_uptime", "kwargs": {"api_summary": {"api": "summary"}}},
|
||||
"config": {"cmd": "get_config", "kwargs": {}},
|
||||
}
|
||||
BTMINER_DATA_LOC = DataLocations(
|
||||
**{
|
||||
str(DataOptions.MAC): DataFunction(
|
||||
"_get_mac",
|
||||
[
|
||||
RPCAPICommand("api_summary", "summary"),
|
||||
RPCAPICommand("api_get_miner_info", "get_miner_info"),
|
||||
],
|
||||
),
|
||||
str(DataOptions.API_VERSION): DataFunction(
|
||||
"_get_api_ver", [RPCAPICommand("api_get_version", "get_version")]
|
||||
),
|
||||
str(DataOptions.FW_VERSION): DataFunction(
|
||||
"_get_fw_ver",
|
||||
[
|
||||
RPCAPICommand("api_get_version", "get_version"),
|
||||
RPCAPICommand("api_summary", "summary"),
|
||||
],
|
||||
),
|
||||
str(DataOptions.HOSTNAME): DataFunction(
|
||||
"_get_hostname", [RPCAPICommand("api_get_miner_info", "get_miner_info")]
|
||||
),
|
||||
str(DataOptions.HASHRATE): DataFunction(
|
||||
"_get_hashrate", [RPCAPICommand("api_summary", "summary")]
|
||||
),
|
||||
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
|
||||
"_get_expected_hashrate", [RPCAPICommand("api_summary", "summary")]
|
||||
),
|
||||
str(DataOptions.HASHBOARDS): DataFunction(
|
||||
"_get_hashboards", [RPCAPICommand("api_devs", "devs")]
|
||||
),
|
||||
str(DataOptions.ENVIRONMENT_TEMP): DataFunction(
|
||||
"_get_env_temp", [RPCAPICommand("api_summary", "summary")]
|
||||
),
|
||||
str(DataOptions.WATTAGE): DataFunction(
|
||||
"_get_wattage", [RPCAPICommand("api_summary", "summary")]
|
||||
),
|
||||
str(DataOptions.WATTAGE_LIMIT): DataFunction(
|
||||
"_get_wattage_limit", [RPCAPICommand("api_summary", "summary")]
|
||||
),
|
||||
str(DataOptions.FANS): DataFunction(
|
||||
"_get_fans",
|
||||
[
|
||||
RPCAPICommand("api_summary", "summary"),
|
||||
RPCAPICommand("api_get_psu", "get_psu"),
|
||||
],
|
||||
),
|
||||
str(DataOptions.FAN_PSU): DataFunction(
|
||||
"_get_fan_psu",
|
||||
[
|
||||
RPCAPICommand("api_summary", "summary"),
|
||||
RPCAPICommand("api_get_psu", "get_psu"),
|
||||
],
|
||||
),
|
||||
str(DataOptions.ERRORS): DataFunction(
|
||||
"_get_errors",
|
||||
[
|
||||
RPCAPICommand("api_get_error_code", "get_error_code"),
|
||||
RPCAPICommand("api_summary", "summary"),
|
||||
],
|
||||
),
|
||||
str(DataOptions.FAULT_LIGHT): DataFunction(
|
||||
"_get_fault_light",
|
||||
[RPCAPICommand("api_get_miner_info", "get_miner_info")],
|
||||
),
|
||||
str(DataOptions.IS_MINING): DataFunction(
|
||||
"_is_mining", [RPCAPICommand("api_status", "status")]
|
||||
),
|
||||
str(DataOptions.UPTIME): DataFunction(
|
||||
"_get_uptime", [RPCAPICommand("api_summary", "summary")]
|
||||
),
|
||||
str(DataOptions.CONFIG): DataFunction("get_config"),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
class BTMiner(BaseMiner):
|
||||
@@ -227,7 +240,7 @@ class BTMiner(BaseMiner):
|
||||
else:
|
||||
cfg = MinerConfig()
|
||||
|
||||
is_mining = await self.is_mining(status)
|
||||
is_mining = await self._is_mining(status)
|
||||
if not is_mining:
|
||||
cfg.mining_mode = MiningModeConfig.sleep()
|
||||
return cfg
|
||||
@@ -271,7 +284,7 @@ class BTMiner(BaseMiner):
|
||||
### DATA GATHERING FUNCTIONS (get_{some_data}) ###
|
||||
##################################################
|
||||
|
||||
async def get_mac(
|
||||
async def _get_mac(
|
||||
self, api_summary: dict = None, api_get_miner_info: dict = None
|
||||
) -> Optional[str]:
|
||||
if not api_get_miner_info:
|
||||
@@ -297,24 +310,10 @@ class BTMiner(BaseMiner):
|
||||
try:
|
||||
mac = api_summary["SUMMARY"][0]["MAC"]
|
||||
return str(mac).upper()
|
||||
except (KeyError, IndexError):
|
||||
except LookupError:
|
||||
pass
|
||||
|
||||
async def get_version(
|
||||
self, api_get_version: dict = None, api_summary: dict = None
|
||||
) -> Tuple[Optional[str], Optional[str]]:
|
||||
miner_version = namedtuple("MinerVersion", "api_ver fw_ver")
|
||||
api_ver = await self.get_api_ver(api_get_version=api_get_version)
|
||||
fw_ver = await self.get_fw_ver(
|
||||
api_get_version=api_get_version, api_summary=api_summary
|
||||
)
|
||||
return miner_version(api_ver, fw_ver)
|
||||
|
||||
async def get_api_ver(self, api_get_version: dict = None) -> Optional[str]:
|
||||
# Check to see if the version info is already cached
|
||||
if self.api_ver:
|
||||
return self.api_ver
|
||||
|
||||
async def _get_api_ver(self, api_get_version: dict = None) -> Optional[str]:
|
||||
if not api_get_version:
|
||||
try:
|
||||
api_get_version = await self.api.get_version()
|
||||
@@ -337,13 +336,9 @@ class BTMiner(BaseMiner):
|
||||
|
||||
return self.api_ver
|
||||
|
||||
async def get_fw_ver(
|
||||
async def _get_fw_ver(
|
||||
self, api_get_version: dict = None, api_summary: dict = None
|
||||
) -> Optional[str]:
|
||||
# Check to see if the version info is already cached
|
||||
if self.fw_ver:
|
||||
return self.fw_ver
|
||||
|
||||
if not api_get_version:
|
||||
try:
|
||||
api_get_version = await self.api.get_version()
|
||||
@@ -371,12 +366,12 @@ class BTMiner(BaseMiner):
|
||||
self.fw_ver = api_summary["SUMMARY"][0]["Firmware Version"].replace(
|
||||
"'", ""
|
||||
)
|
||||
except (KeyError, IndexError):
|
||||
except LookupError:
|
||||
pass
|
||||
|
||||
return self.fw_ver
|
||||
|
||||
async def get_hostname(self, api_get_miner_info: dict = None) -> Optional[str]:
|
||||
async def _get_hostname(self, api_get_miner_info: dict = None) -> Optional[str]:
|
||||
hostname = None
|
||||
if not api_get_miner_info:
|
||||
try:
|
||||
@@ -392,7 +387,7 @@ class BTMiner(BaseMiner):
|
||||
|
||||
return hostname
|
||||
|
||||
async def get_hashrate(self, api_summary: dict = None) -> Optional[float]:
|
||||
async def _get_hashrate(self, api_summary: dict = None) -> Optional[float]:
|
||||
# get hr from API
|
||||
if not api_summary:
|
||||
try:
|
||||
@@ -403,10 +398,10 @@ class BTMiner(BaseMiner):
|
||||
if api_summary:
|
||||
try:
|
||||
return round(float(api_summary["SUMMARY"][0]["MHS 1m"] / 1000000), 2)
|
||||
except (KeyError, IndexError):
|
||||
except LookupError:
|
||||
pass
|
||||
|
||||
async def get_hashboards(self, api_devs: dict = None) -> List[HashBoard]:
|
||||
async def _get_hashboards(self, api_devs: dict = None) -> List[HashBoard]:
|
||||
hashboards = [
|
||||
HashBoard(slot=i, expected_chips=self.expected_chips)
|
||||
for i in range(self.expected_hashboards)
|
||||
@@ -434,13 +429,14 @@ class BTMiner(BaseMiner):
|
||||
float(board["MHS 1m"] / 1000000), 2
|
||||
)
|
||||
hashboards[board["ASC"]].chips = board["Effective Chips"]
|
||||
hashboards[board["ASC"]].serial_number = board["PCB SN"]
|
||||
hashboards[board["ASC"]].missing = False
|
||||
except (KeyError, IndexError):
|
||||
except LookupError:
|
||||
pass
|
||||
|
||||
return hashboards
|
||||
|
||||
async def get_env_temp(self, api_summary: dict = None) -> Optional[float]:
|
||||
async def _get_env_temp(self, api_summary: dict = None) -> Optional[float]:
|
||||
if not api_summary:
|
||||
try:
|
||||
api_summary = await self.api.summary()
|
||||
@@ -450,10 +446,10 @@ class BTMiner(BaseMiner):
|
||||
if api_summary:
|
||||
try:
|
||||
return api_summary["SUMMARY"][0]["Env Temp"]
|
||||
except (KeyError, IndexError):
|
||||
except LookupError:
|
||||
pass
|
||||
|
||||
async def get_wattage(self, api_summary: dict = None) -> Optional[int]:
|
||||
async def _get_wattage(self, api_summary: dict = None) -> Optional[int]:
|
||||
if not api_summary:
|
||||
try:
|
||||
api_summary = await self.api.summary()
|
||||
@@ -464,10 +460,10 @@ class BTMiner(BaseMiner):
|
||||
try:
|
||||
wattage = api_summary["SUMMARY"][0]["Power"]
|
||||
return wattage if not wattage == -1 else None
|
||||
except (KeyError, IndexError):
|
||||
except LookupError:
|
||||
pass
|
||||
|
||||
async def get_wattage_limit(self, api_summary: dict = None) -> Optional[int]:
|
||||
async def _get_wattage_limit(self, api_summary: dict = None) -> Optional[int]:
|
||||
if not api_summary:
|
||||
try:
|
||||
api_summary = await self.api.summary()
|
||||
@@ -477,10 +473,10 @@ class BTMiner(BaseMiner):
|
||||
if api_summary:
|
||||
try:
|
||||
return api_summary["SUMMARY"][0]["Power Limit"]
|
||||
except (KeyError, IndexError):
|
||||
except LookupError:
|
||||
pass
|
||||
|
||||
async def get_fans(
|
||||
async def _get_fans(
|
||||
self, api_summary: dict = None, api_get_psu: dict = None
|
||||
) -> List[Fan]:
|
||||
if not api_summary:
|
||||
@@ -489,20 +485,20 @@ class BTMiner(BaseMiner):
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
fans = [Fan() for _ in range(self.fan_count)]
|
||||
fans = [Fan() for _ in range(self.expected_fans)]
|
||||
if api_summary:
|
||||
try:
|
||||
if self.fan_count > 0:
|
||||
if self.expected_fans > 0:
|
||||
fans = [
|
||||
Fan(api_summary["SUMMARY"][0].get("Fan Speed In", 0)),
|
||||
Fan(api_summary["SUMMARY"][0].get("Fan Speed Out", 0)),
|
||||
]
|
||||
except (KeyError, IndexError):
|
||||
except LookupError:
|
||||
pass
|
||||
|
||||
return fans
|
||||
|
||||
async def get_fan_psu(
|
||||
async def _get_fan_psu(
|
||||
self, api_summary: dict = None, api_get_psu: dict = None
|
||||
) -> Optional[int]:
|
||||
if not api_summary:
|
||||
@@ -514,7 +510,7 @@ class BTMiner(BaseMiner):
|
||||
if api_summary:
|
||||
try:
|
||||
return int(api_summary["SUMMARY"][0]["Power Fanspeed"])
|
||||
except (KeyError, IndexError):
|
||||
except LookupError:
|
||||
pass
|
||||
|
||||
if not api_get_psu:
|
||||
@@ -529,52 +525,11 @@ class BTMiner(BaseMiner):
|
||||
except (KeyError, TypeError):
|
||||
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
|
||||
) -> List[MinerErrorData]:
|
||||
errors = []
|
||||
if not api_summary and not api_get_error_code:
|
||||
try:
|
||||
api_summary = await self.api.summary()
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
if api_summary:
|
||||
try:
|
||||
for i in range(api_summary["SUMMARY"][0]["Error Code Count"]):
|
||||
err = api_summary["SUMMARY"][0].get(f"Error Code {i}")
|
||||
if err:
|
||||
errors.append(WhatsminerError(error_code=err))
|
||||
except (KeyError, IndexError, ValueError, TypeError):
|
||||
pass
|
||||
|
||||
if not api_get_error_code:
|
||||
if not api_get_error_code and not api_summary:
|
||||
try:
|
||||
api_get_error_code = await self.api.get_error_code()
|
||||
except APIError:
|
||||
@@ -588,9 +543,23 @@ class BTMiner(BaseMiner):
|
||||
else:
|
||||
errors.append(WhatsminerError(error_code=int(err)))
|
||||
|
||||
if not api_summary:
|
||||
try:
|
||||
api_summary = await self.api.summary()
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
if api_summary:
|
||||
try:
|
||||
for i in range(api_summary["SUMMARY"][0]["Error Code Count"]):
|
||||
err = api_summary["SUMMARY"][0].get(f"Error Code {i}")
|
||||
if err:
|
||||
errors.append(WhatsminerError(error_code=err))
|
||||
except (LookupError, ValueError, TypeError):
|
||||
pass
|
||||
return errors
|
||||
|
||||
async def get_expected_hashrate(self, api_summary: dict = None):
|
||||
async def _get_expected_hashrate(self, api_summary: dict = None):
|
||||
if not api_summary:
|
||||
try:
|
||||
api_summary = await self.api.summary()
|
||||
@@ -602,10 +571,10 @@ class BTMiner(BaseMiner):
|
||||
expected_hashrate = api_summary["SUMMARY"][0]["Factory GHS"]
|
||||
if expected_hashrate:
|
||||
return round(expected_hashrate / 1000, 2)
|
||||
except (KeyError, IndexError):
|
||||
except LookupError:
|
||||
pass
|
||||
|
||||
async def get_fault_light(self, api_get_miner_info: dict = None) -> bool:
|
||||
async def _get_fault_light(self, api_get_miner_info: dict = None) -> bool:
|
||||
if not api_get_miner_info:
|
||||
try:
|
||||
api_get_miner_info = await self.api.get_miner_info()
|
||||
@@ -643,7 +612,7 @@ class BTMiner(BaseMiner):
|
||||
async def set_hostname(self, hostname: str):
|
||||
await self.api.set_hostname(hostname)
|
||||
|
||||
async def is_mining(self, api_status: dict = None) -> Optional[bool]:
|
||||
async def _is_mining(self, api_status: dict = None) -> Optional[bool]:
|
||||
if not api_status:
|
||||
try:
|
||||
api_status = await self.api.status()
|
||||
@@ -662,7 +631,7 @@ class BTMiner(BaseMiner):
|
||||
except LookupError:
|
||||
pass
|
||||
|
||||
async def get_uptime(self, api_summary: dict = None) -> Optional[int]:
|
||||
async def _get_uptime(self, api_summary: dict = None) -> Optional[int]:
|
||||
if not api_summary:
|
||||
try:
|
||||
api_summary = await self.api.summary()
|
||||
|
||||
@@ -15,40 +15,56 @@
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
import logging
|
||||
from collections import namedtuple
|
||||
from typing import List, Optional, Tuple
|
||||
from typing import List, Optional
|
||||
|
||||
from pyasic.API.cgminer import CGMinerAPI
|
||||
from pyasic.config import MinerConfig
|
||||
from pyasic.data import Fan, HashBoard
|
||||
from pyasic.data.error_codes import MinerErrorData
|
||||
from pyasic.errors import APIError
|
||||
from pyasic.miners.base import BaseMiner
|
||||
from pyasic.miners.base import (
|
||||
BaseMiner,
|
||||
DataFunction,
|
||||
DataLocations,
|
||||
DataOptions,
|
||||
RPCAPICommand,
|
||||
)
|
||||
|
||||
CGMINER_DATA_LOC = {
|
||||
"mac": {"cmd": "get_mac", "kwargs": {}},
|
||||
"model": {"cmd": "get_model", "kwargs": {}},
|
||||
"api_ver": {"cmd": "get_api_ver", "kwargs": {"api_version": {"api": "version"}}},
|
||||
"fw_ver": {"cmd": "get_fw_ver", "kwargs": {"api_version": {"api": "version"}}},
|
||||
"hostname": {"cmd": "get_hostname", "kwargs": {}},
|
||||
"hashrate": {"cmd": "get_hashrate", "kwargs": {"api_summary": {"api": "summary"}}},
|
||||
"expected_hashrate": {
|
||||
"cmd": "get_expected_hashrate",
|
||||
"kwargs": {"api_stats": {"api": "stats"}},
|
||||
},
|
||||
"hashboards": {"cmd": "get_hashboards", "kwargs": {"api_stats": {"api": "stats"}}},
|
||||
"env_temp": {"cmd": "get_env_temp", "kwargs": {}},
|
||||
"wattage": {"cmd": "get_wattage", "kwargs": {}},
|
||||
"wattage_limit": {"cmd": "get_wattage_limit", "kwargs": {}},
|
||||
"fans": {"cmd": "get_fans", "kwargs": {"api_stats": {"api": "stats"}}},
|
||||
"fan_psu": {"cmd": "get_fan_psu", "kwargs": {}},
|
||||
"errors": {"cmd": "get_errors", "kwargs": {}},
|
||||
"fault_light": {"cmd": "get_fault_light", "kwargs": {}},
|
||||
"pools": {"cmd": "get_pools", "kwargs": {"api_pools": {"api": "pools"}}},
|
||||
"is_mining": {"cmd": "is_mining", "kwargs": {}},
|
||||
"uptime": {"cmd": "get_uptime", "kwargs": {"api_stats": {"api": "stats"}}},
|
||||
"config": {"cmd": "get_config", "kwargs": {}},
|
||||
}
|
||||
CGMINER_DATA_LOC = DataLocations(
|
||||
**{
|
||||
str(DataOptions.MAC): DataFunction("_get_mac"),
|
||||
str(DataOptions.API_VERSION): DataFunction(
|
||||
"_get_api_ver", [RPCAPICommand("api_version", "version")]
|
||||
),
|
||||
str(DataOptions.FW_VERSION): DataFunction(
|
||||
"_get_fw_ver", [RPCAPICommand("api_version", "version")]
|
||||
),
|
||||
str(DataOptions.HOSTNAME): DataFunction("_get_hostname"),
|
||||
str(DataOptions.HASHRATE): DataFunction(
|
||||
"_get_hashrate", [RPCAPICommand("api_summary", "summary")]
|
||||
),
|
||||
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
|
||||
"_get_expected_hashrate", [RPCAPICommand("api_stats", "stats")]
|
||||
),
|
||||
str(DataOptions.HASHBOARDS): DataFunction(
|
||||
"_get_hashboards", [RPCAPICommand("api_stats", "stats")]
|
||||
),
|
||||
str(DataOptions.ENVIRONMENT_TEMP): DataFunction("_get_env_temp"),
|
||||
str(DataOptions.WATTAGE): DataFunction("_get_wattage"),
|
||||
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):
|
||||
@@ -94,11 +110,9 @@ class CGMiner(BaseMiner):
|
||||
return result
|
||||
|
||||
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()
|
||||
|
||||
async def restart_cgminer(self) -> bool:
|
||||
"""Restart cgminer hashing process."""
|
||||
commands = ["cgminer-api restart", "/usr/bin/cgminer-monitor >/dev/null 2>&1"]
|
||||
commands = ";".join(commands)
|
||||
ret = await self.send_ssh_command(commands)
|
||||
@@ -107,7 +121,6 @@ class CGMiner(BaseMiner):
|
||||
return True
|
||||
|
||||
async def reboot(self) -> bool:
|
||||
"""Reboots power to the physical miner."""
|
||||
logging.debug(f"{self}: Sending reboot command.")
|
||||
ret = await self.send_ssh_command("reboot")
|
||||
if ret is None:
|
||||
@@ -166,22 +179,10 @@ class CGMiner(BaseMiner):
|
||||
### DATA GATHERING FUNCTIONS (get_{some_data}) ###
|
||||
##################################################
|
||||
|
||||
async def get_mac(self) -> Optional[str]:
|
||||
async def _get_mac(self) -> Optional[str]:
|
||||
return None
|
||||
|
||||
async def get_version(
|
||||
self, api_version: dict = None
|
||||
) -> Tuple[Optional[str], Optional[str]]:
|
||||
miner_version = namedtuple("MinerVersion", "api_ver fw_ver")
|
||||
return miner_version(
|
||||
api_ver=await self.get_api_ver(api_version=api_version),
|
||||
fw_ver=await self.get_fw_ver(api_version=api_version),
|
||||
)
|
||||
|
||||
async def get_api_ver(self, api_version: dict = None) -> Optional[str]:
|
||||
if self.api_ver:
|
||||
return self.api_ver
|
||||
|
||||
async def _get_api_ver(self, api_version: dict = None) -> Optional[str]:
|
||||
if not api_version:
|
||||
try:
|
||||
api_version = await self.api.version()
|
||||
@@ -191,15 +192,12 @@ class CGMiner(BaseMiner):
|
||||
if api_version:
|
||||
try:
|
||||
self.api_ver = api_version["VERSION"][0]["API"]
|
||||
except (KeyError, IndexError):
|
||||
except LookupError:
|
||||
pass
|
||||
|
||||
return self.api_ver
|
||||
|
||||
async def get_fw_ver(self, api_version: dict = None) -> Optional[str]:
|
||||
if self.fw_ver:
|
||||
return self.fw_ver
|
||||
|
||||
async def _get_fw_ver(self, api_version: dict = None) -> Optional[str]:
|
||||
if not api_version:
|
||||
try:
|
||||
api_version = await self.api.version()
|
||||
@@ -209,16 +207,16 @@ class CGMiner(BaseMiner):
|
||||
if api_version:
|
||||
try:
|
||||
self.fw_ver = api_version["VERSION"][0]["CGMiner"]
|
||||
except (KeyError, IndexError):
|
||||
except LookupError:
|
||||
pass
|
||||
|
||||
return self.fw_ver
|
||||
|
||||
async def get_hostname(self) -> Optional[str]:
|
||||
async def _get_hostname(self) -> Optional[str]:
|
||||
hn = await self.send_ssh_command("cat /proc/sys/kernel/hostname")
|
||||
return hn
|
||||
|
||||
async def get_hashrate(self, api_summary: dict = None) -> Optional[float]:
|
||||
async def _get_hashrate(self, api_summary: dict = None) -> Optional[float]:
|
||||
# get hr from API
|
||||
if not api_summary:
|
||||
try:
|
||||
@@ -231,10 +229,10 @@ class CGMiner(BaseMiner):
|
||||
return round(
|
||||
float(float(api_summary["SUMMARY"][0]["GHS 5s"]) / 1000), 2
|
||||
)
|
||||
except (IndexError, KeyError, ValueError, TypeError):
|
||||
except (LookupError, ValueError, TypeError):
|
||||
pass
|
||||
|
||||
async def get_hashboards(self, api_stats: dict = None) -> List[HashBoard]:
|
||||
async def _get_hashboards(self, api_stats: dict = None) -> List[HashBoard]:
|
||||
hashboards = []
|
||||
|
||||
if not api_stats:
|
||||
@@ -283,28 +281,28 @@ class CGMiner(BaseMiner):
|
||||
if (not chips) or (not chips > 0):
|
||||
hashboard.missing = True
|
||||
hashboards.append(hashboard)
|
||||
except (IndexError, KeyError, ValueError, TypeError):
|
||||
except (LookupError, ValueError, TypeError):
|
||||
pass
|
||||
|
||||
return hashboards
|
||||
|
||||
async def get_env_temp(self) -> Optional[float]:
|
||||
async def _get_env_temp(self) -> Optional[float]:
|
||||
return None
|
||||
|
||||
async def get_wattage(self) -> Optional[int]:
|
||||
async def _get_wattage(self) -> Optional[int]:
|
||||
return None
|
||||
|
||||
async def get_wattage_limit(self) -> Optional[int]:
|
||||
async def _get_wattage_limit(self) -> Optional[int]:
|
||||
return None
|
||||
|
||||
async def get_fans(self, api_stats: dict = None) -> List[Fan]:
|
||||
async def _get_fans(self, api_stats: dict = None) -> List[Fan]:
|
||||
if not api_stats:
|
||||
try:
|
||||
api_stats = await self.api.stats()
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
fans = [Fan() for _ in range(self.fan_count)]
|
||||
fans = [Fan() for _ in range(self.expected_fans)]
|
||||
if api_stats:
|
||||
try:
|
||||
fan_offset = -1
|
||||
@@ -317,50 +315,24 @@ class CGMiner(BaseMiner):
|
||||
if fan_offset == -1:
|
||||
fan_offset = 1
|
||||
|
||||
for fan in range(self.fan_count):
|
||||
for fan in range(self.expected_fans):
|
||||
fans[fan].speed = api_stats["STATS"][1].get(
|
||||
f"fan{fan_offset+fan}", 0
|
||||
)
|
||||
except (KeyError, IndexError):
|
||||
except LookupError:
|
||||
pass
|
||||
return fans
|
||||
|
||||
async def get_fan_psu(self) -> Optional[int]:
|
||||
async def _get_fan_psu(self) -> Optional[int]:
|
||||
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 []
|
||||
|
||||
async def get_fault_light(self) -> bool:
|
||||
async def _get_fault_light(self) -> bool:
|
||||
return False
|
||||
|
||||
async def get_expected_hashrate(self, api_stats: dict = None) -> Optional[float]:
|
||||
async def _get_expected_hashrate(self, api_stats: dict = None) -> Optional[float]:
|
||||
# X19 method, not sure compatibility
|
||||
if not api_stats:
|
||||
try:
|
||||
@@ -381,13 +353,13 @@ class CGMiner(BaseMiner):
|
||||
return round(expected_rate / 1000000, 2)
|
||||
else:
|
||||
return round(expected_rate, 2)
|
||||
except (KeyError, IndexError):
|
||||
except LookupError:
|
||||
pass
|
||||
|
||||
async def is_mining(self, *args, **kwargs) -> Optional[bool]:
|
||||
async def _is_mining(self, *args, **kwargs) -> Optional[bool]:
|
||||
return None
|
||||
|
||||
async def get_uptime(self, api_stats: dict = None) -> Optional[int]:
|
||||
async def _get_uptime(self, api_stats: dict = None) -> Optional[int]:
|
||||
if not api_stats:
|
||||
try:
|
||||
api_stats = await self.api.stats()
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
import logging
|
||||
import re
|
||||
from typing import List, Optional
|
||||
|
||||
@@ -23,37 +22,49 @@ from pyasic.data import Fan, HashBoard
|
||||
from pyasic.data.error_codes import MinerErrorData
|
||||
from pyasic.errors import APIError
|
||||
from pyasic.miners.backends import CGMiner
|
||||
from pyasic.miners.base import DataFunction, DataLocations, DataOptions, RPCAPICommand
|
||||
|
||||
AVALON_DATA_LOC = {
|
||||
"mac": {"cmd": "get_mac", "kwargs": {"api_version": {"api": "version"}}},
|
||||
"model": {"cmd": "get_model", "kwargs": {}},
|
||||
"api_ver": {"cmd": "get_api_ver", "kwargs": {"api_version": {"api": "version"}}},
|
||||
"fw_ver": {"cmd": "get_fw_ver", "kwargs": {"api_version": {"api": "version"}}},
|
||||
"hostname": {"cmd": "get_hostname", "kwargs": {"mac": {"api": "version"}}},
|
||||
"hashrate": {"cmd": "get_hashrate", "kwargs": {"api_devs": {"api": "devs"}}},
|
||||
"expected_hashrate": {
|
||||
"cmd": "get_expected_hashrate",
|
||||
"kwargs": {"api_stats": {"api": "stats"}},
|
||||
},
|
||||
"hashboards": {"cmd": "get_hashboards", "kwargs": {"api_stats": {"api": "stats"}}},
|
||||
"env_temp": {"cmd": "get_env_temp", "kwargs": {"api_stats": {"api": "stats"}}},
|
||||
"wattage": {"cmd": "get_wattage", "kwargs": {}},
|
||||
"wattage_limit": {
|
||||
"cmd": "get_wattage_limit",
|
||||
"kwargs": {"api_stats": {"api": "stats"}},
|
||||
},
|
||||
"fans": {"cmd": "get_fans", "kwargs": {"api_stats": {"api": "stats"}}},
|
||||
"fan_psu": {"cmd": "get_fan_psu", "kwargs": {}},
|
||||
"errors": {"cmd": "get_errors", "kwargs": {}},
|
||||
"fault_light": {
|
||||
"cmd": "get_fault_light",
|
||||
"kwargs": {"api_stats": {"api": "stats"}},
|
||||
},
|
||||
"pools": {"cmd": "get_pools", "kwargs": {"api_pools": {"api": "pools"}}},
|
||||
"is_mining": {"cmd": "is_mining", "kwargs": {}},
|
||||
"uptime": {"cmd": "get_uptime", "kwargs": {}},
|
||||
"config": {"cmd": "get_config", "kwargs": {}},
|
||||
}
|
||||
AVALON_DATA_LOC = DataLocations(
|
||||
**{
|
||||
str(DataOptions.MAC): DataFunction(
|
||||
"_get_mac", [RPCAPICommand("api_version", "version")]
|
||||
),
|
||||
str(DataOptions.API_VERSION): DataFunction(
|
||||
"_get_api_ver", [RPCAPICommand("api_version", "version")]
|
||||
),
|
||||
str(DataOptions.FW_VERSION): DataFunction(
|
||||
"_get_fw_ver", [RPCAPICommand("api_version", "version")]
|
||||
),
|
||||
str(DataOptions.HOSTNAME): DataFunction("_get_hostname"),
|
||||
str(DataOptions.HASHRATE): DataFunction(
|
||||
"_get_hashrate", [RPCAPICommand("api_devs", "devs")]
|
||||
),
|
||||
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
|
||||
"_get_expected_hashrate", [RPCAPICommand("api_stats", "stats")]
|
||||
),
|
||||
str(DataOptions.HASHBOARDS): DataFunction(
|
||||
"_get_hashboards", [RPCAPICommand("api_stats", "stats")]
|
||||
),
|
||||
str(DataOptions.ENVIRONMENT_TEMP): DataFunction(
|
||||
"_get_env_temp", [RPCAPICommand("api_stats", "stats")]
|
||||
),
|
||||
str(DataOptions.WATTAGE): DataFunction("_get_wattage"),
|
||||
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):
|
||||
@@ -116,7 +127,7 @@ class CGMinerAvalon(CGMiner):
|
||||
|
||||
@staticmethod
|
||||
def parse_stats(stats):
|
||||
_stats_items = re.findall(".+?\[*?]", stats)
|
||||
_stats_items = re.findall(".+?\\[*?]", stats)
|
||||
stats_items = []
|
||||
stats_dict = {}
|
||||
for item in _stats_items:
|
||||
@@ -161,7 +172,7 @@ class CGMinerAvalon(CGMiner):
|
||||
### DATA GATHERING FUNCTIONS (get_{some_data}) ###
|
||||
##################################################
|
||||
|
||||
async def get_mac(self, api_version: dict = None) -> Optional[str]:
|
||||
async def _get_mac(self, api_version: dict = None) -> Optional[str]:
|
||||
if not api_version:
|
||||
try:
|
||||
api_version = await self.api.version()
|
||||
@@ -179,7 +190,7 @@ class CGMinerAvalon(CGMiner):
|
||||
except (KeyError, ValueError):
|
||||
pass
|
||||
|
||||
async def get_hostname(self, mac: str = None) -> Optional[str]:
|
||||
async def _get_hostname(self) -> Optional[str]:
|
||||
return None
|
||||
# if not mac:
|
||||
# mac = await self.get_mac()
|
||||
@@ -187,7 +198,7 @@ class CGMinerAvalon(CGMiner):
|
||||
# if mac:
|
||||
# return f"Avalon{mac.replace(':', '')[-6:]}"
|
||||
|
||||
async def get_hashrate(self, api_devs: dict = None) -> Optional[float]:
|
||||
async def _get_hashrate(self, api_devs: dict = None) -> Optional[float]:
|
||||
if not api_devs:
|
||||
try:
|
||||
api_devs = await self.api.devs()
|
||||
@@ -200,7 +211,7 @@ class CGMinerAvalon(CGMiner):
|
||||
except (KeyError, IndexError, ValueError, TypeError):
|
||||
pass
|
||||
|
||||
async def get_hashboards(self, api_stats: dict = None) -> List[HashBoard]:
|
||||
async def _get_hashboards(self, api_stats: dict = None) -> List[HashBoard]:
|
||||
hashboards = [
|
||||
HashBoard(slot=i, expected_chips=self.expected_chips)
|
||||
for i in range(self.expected_hashboards)
|
||||
@@ -248,7 +259,7 @@ class CGMinerAvalon(CGMiner):
|
||||
|
||||
return hashboards
|
||||
|
||||
async def get_expected_hashrate(self, api_stats: dict = None) -> Optional[float]:
|
||||
async def _get_expected_hashrate(self, api_stats: dict = None) -> Optional[float]:
|
||||
if not api_stats:
|
||||
try:
|
||||
api_stats = await self.api.stats()
|
||||
@@ -263,7 +274,7 @@ class CGMinerAvalon(CGMiner):
|
||||
except (IndexError, KeyError, ValueError, TypeError):
|
||||
pass
|
||||
|
||||
async def get_env_temp(self, api_stats: dict = None) -> Optional[float]:
|
||||
async def _get_env_temp(self, api_stats: dict = None) -> Optional[float]:
|
||||
if not api_stats:
|
||||
try:
|
||||
api_stats = await self.api.stats()
|
||||
@@ -278,10 +289,10 @@ class CGMinerAvalon(CGMiner):
|
||||
except (IndexError, KeyError, ValueError, TypeError):
|
||||
pass
|
||||
|
||||
async def get_wattage(self) -> Optional[int]:
|
||||
async def _get_wattage(self) -> Optional[int]:
|
||||
return None
|
||||
|
||||
async def get_wattage_limit(self, api_stats: dict = None) -> Optional[int]:
|
||||
async def _get_wattage_limit(self, api_stats: dict = None) -> Optional[int]:
|
||||
if not api_stats:
|
||||
try:
|
||||
api_stats = await self.api.stats()
|
||||
@@ -296,14 +307,14 @@ class CGMinerAvalon(CGMiner):
|
||||
except (IndexError, KeyError, ValueError, TypeError):
|
||||
pass
|
||||
|
||||
async def get_fans(self, api_stats: dict = None) -> List[Fan]:
|
||||
async def _get_fans(self, api_stats: dict = None) -> List[Fan]:
|
||||
if not api_stats:
|
||||
try:
|
||||
api_stats = await self.api.stats()
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
fans_data = [Fan() for _ in range(self.fan_count)]
|
||||
fans_data = [Fan() for _ in range(self.expected_fans)]
|
||||
if api_stats:
|
||||
try:
|
||||
unparsed_stats = api_stats["STATS"][0]["MM ID0"]
|
||||
@@ -311,43 +322,17 @@ class CGMinerAvalon(CGMiner):
|
||||
except LookupError:
|
||||
return fans_data
|
||||
|
||||
for fan in range(self.fan_count):
|
||||
for fan in range(self.expected_fans):
|
||||
try:
|
||||
fans_data[fan].speed = int(parsed_stats[f"Fan{fan + 1}"])
|
||||
except (IndexError, KeyError, ValueError, TypeError):
|
||||
pass
|
||||
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 []
|
||||
|
||||
async def get_fault_light(self, api_stats: dict = None) -> bool: # noqa
|
||||
async def _get_fault_light(self, api_stats: dict = None) -> bool: # noqa
|
||||
if self.light:
|
||||
return self.light
|
||||
if not api_stats:
|
||||
@@ -376,5 +361,8 @@ class CGMinerAvalon(CGMiner):
|
||||
pass
|
||||
return False
|
||||
|
||||
async def is_mining(self, *args, **kwargs) -> Optional[bool]:
|
||||
async def _is_mining(self, *args, **kwargs) -> Optional[bool]:
|
||||
return None
|
||||
|
||||
async def _get_uptime(self) -> Optional[int]:
|
||||
return None
|
||||
|
||||
@@ -14,51 +14,72 @@
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
from typing import List, Optional, Tuple, Union
|
||||
from typing import List, Optional
|
||||
|
||||
from pyasic.config import MinerConfig
|
||||
from pyasic.data import Fan, HashBoard
|
||||
from pyasic.data.error_codes import MinerErrorData, X19Error
|
||||
from pyasic.errors import APIError
|
||||
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
|
||||
|
||||
EPIC_DATA_LOC = {
|
||||
"mac": {"cmd": "get_mac", "kwargs": {"web_summary": {"web": "network"}}},
|
||||
"model": {"cmd": "get_model", "kwargs": {}},
|
||||
"api_ver": {"cmd": "get_api_ver", "kwargs": {"api_version": {"api": "version"}}},
|
||||
"fw_ver": {"cmd": "get_fw_ver", "kwargs": {"web_summary": {"web": "summary"}}},
|
||||
"hostname": {"cmd": "get_hostname", "kwargs": {"web_summary": {"web": "summary"}}},
|
||||
"hashrate": {"cmd": "get_hashrate", "kwargs": {"web_summary": {"web": "summary"}}},
|
||||
"expected_hashrate": {
|
||||
"cmd": "get_expected_hashrate",
|
||||
"kwargs": {"web_summary": {"web": "summary"}},
|
||||
},
|
||||
"hashboards": {
|
||||
"cmd": "get_hashboards",
|
||||
"kwargs": {
|
||||
"web_summary": {"web": "summary"},
|
||||
"web_hashrate": {"web": "hashrate"},
|
||||
},
|
||||
},
|
||||
"env_temp": {"cmd": "get_env_temp", "kwargs": {}},
|
||||
"wattage": {"cmd": "get_wattage", "kwargs": {"web_summary": {"web": "summary"}}},
|
||||
"wattage_limit": {"cmd": "get_wattage_limit", "kwargs": {}},
|
||||
"fans": {"cmd": "get_fans", "kwargs": {"web_summary": {"web": "summary"}}},
|
||||
"fan_psu": {"cmd": "get_fan_psu", "kwargs": {}},
|
||||
"fault_light": {
|
||||
"cmd": "get_fault_light",
|
||||
"kwargs": {"web_summary": {"web": "summary"}},
|
||||
},
|
||||
"pools": {"cmd": "get_pools", "kwargs": {"web_summary": {"web": "summary"}}},
|
||||
"is_mining": {"cmd": "is_mining", "kwargs": {}},
|
||||
"uptime": {"cmd": "get_uptime", "kwargs": {"web_summary": {"web": "summary"}}},
|
||||
"errors": {"cmd": "get_errors", "kwargs": {"web_summary": {"web": "summary"}}},
|
||||
"config": {"cmd": "get_config", "kwargs": {}},
|
||||
}
|
||||
EPIC_DATA_LOC = DataLocations(
|
||||
**{
|
||||
str(DataOptions.MAC): DataFunction(
|
||||
"_get_mac", [WebAPICommand("web_network", "network")]
|
||||
),
|
||||
str(DataOptions.API_VERSION): DataFunction("_get_api_ver"),
|
||||
str(DataOptions.FW_VERSION): DataFunction(
|
||||
"_get_fw_ver", [WebAPICommand("web_summary", "summary")]
|
||||
),
|
||||
str(DataOptions.HOSTNAME): DataFunction(
|
||||
"_get_hostname", [WebAPICommand("web_summary", "summary")]
|
||||
),
|
||||
str(DataOptions.HASHRATE): DataFunction(
|
||||
"_get_hashrate", [WebAPICommand("web_summary", "summary")]
|
||||
),
|
||||
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
|
||||
"_get_expected_hashrate", [WebAPICommand("web_summary", "summary")]
|
||||
),
|
||||
str(DataOptions.HASHBOARDS): DataFunction(
|
||||
"_get_hashboards",
|
||||
[
|
||||
WebAPICommand("web_summary", "summary"),
|
||||
WebAPICommand("web_hashrate", "hashrate"),
|
||||
],
|
||||
),
|
||||
str(DataOptions.ENVIRONMENT_TEMP): DataFunction("_get_env_temp"),
|
||||
str(DataOptions.WATTAGE): DataFunction(
|
||||
"_get_wattage", [WebAPICommand("web_summary", "summary")]
|
||||
),
|
||||
str(DataOptions.WATTAGE_LIMIT): DataFunction("_get_wattage_limit"),
|
||||
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:
|
||||
super().__init__(ip, api_ver)
|
||||
# interfaces
|
||||
@@ -66,13 +87,26 @@ class ePIC(BMMiner):
|
||||
|
||||
# static data
|
||||
self.api_type = "ePIC"
|
||||
self.fw_str = "ePIC"
|
||||
# data gathering locations
|
||||
self.data_locations = EPIC_DATA_LOC
|
||||
|
||||
async def get_model(self) -> Optional[str]:
|
||||
if self.model is not None:
|
||||
return self.model + " (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:
|
||||
data = await self.web.restart_epic()
|
||||
@@ -110,18 +144,18 @@ class ePIC(BMMiner):
|
||||
pass
|
||||
return False
|
||||
|
||||
async def get_mac(self, web_summary: dict = None) -> str:
|
||||
if not web_summary:
|
||||
web_summary = await self.web.network()
|
||||
if web_summary:
|
||||
async def _get_mac(self, web_network: dict = None) -> str:
|
||||
if not web_network:
|
||||
web_network = await self.web.network()
|
||||
if web_network:
|
||||
try:
|
||||
for network in web_summary:
|
||||
mac = web_summary[network]["mac_address"]
|
||||
return mac
|
||||
for network in web_network:
|
||||
mac = web_network[network]["mac_address"]
|
||||
return mac
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
async def get_hostname(self, web_summary: dict = None) -> str:
|
||||
async def _get_hostname(self, web_summary: dict = None) -> str:
|
||||
if not web_summary:
|
||||
web_summary = await self.web.summary()
|
||||
if web_summary:
|
||||
@@ -131,7 +165,7 @@ class ePIC(BMMiner):
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
async def get_wattage(self, web_summary: dict = None) -> Optional[int]:
|
||||
async def _get_wattage(self, web_summary: dict = None) -> Optional[int]:
|
||||
if not web_summary:
|
||||
web_summary = await self.web.summary()
|
||||
|
||||
@@ -143,7 +177,7 @@ class ePIC(BMMiner):
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
async def get_hashrate(self, web_summary: dict = None) -> Optional[float]:
|
||||
async def _get_hashrate(self, web_summary: dict = None) -> Optional[float]:
|
||||
# get hr from API
|
||||
if not web_summary:
|
||||
try:
|
||||
@@ -154,7 +188,7 @@ class ePIC(BMMiner):
|
||||
if web_summary:
|
||||
try:
|
||||
hashrate = 0
|
||||
if web_summary["HBs"] != None:
|
||||
if web_summary["HBs"] is not None:
|
||||
for hb in web_summary["HBs"]:
|
||||
hashrate += hb["Hashrate"][0]
|
||||
return round(float(float(hashrate / 1000000)), 2)
|
||||
@@ -162,7 +196,7 @@ class ePIC(BMMiner):
|
||||
logger.error(e)
|
||||
pass
|
||||
|
||||
async def get_expected_hashrate(self, web_summary: dict = None) -> Optional[float]:
|
||||
async def _get_expected_hashrate(self, web_summary: dict = None) -> Optional[float]:
|
||||
# get hr from API
|
||||
if not web_summary:
|
||||
try:
|
||||
@@ -173,7 +207,7 @@ class ePIC(BMMiner):
|
||||
if web_summary:
|
||||
try:
|
||||
hashrate = 0
|
||||
if web_summary["HBs"] != None:
|
||||
if web_summary["HBs"] is not None:
|
||||
for hb in web_summary["HBs"]:
|
||||
if hb["Hashrate"][1] == 0:
|
||||
ideal = 1.0
|
||||
@@ -182,11 +216,11 @@ class ePIC(BMMiner):
|
||||
|
||||
hashrate += hb["Hashrate"][0] / ideal
|
||||
return round(float(float(hashrate / 1000000)), 2)
|
||||
except (IndexError, KeyError, ValueError, TypeError) as e:
|
||||
except (LookupError, ValueError, TypeError) as e:
|
||||
logger.error(e)
|
||||
pass
|
||||
|
||||
async def get_fw_ver(self, web_summary: dict = None) -> Optional[str]:
|
||||
async def _get_fw_ver(self, web_summary: dict = None) -> Optional[str]:
|
||||
if not web_summary:
|
||||
web_summary = await self.web.summary()
|
||||
|
||||
@@ -198,7 +232,7 @@ class ePIC(BMMiner):
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
async def get_fans(self, web_summary: dict = None) -> List[Fan]:
|
||||
async def _get_fans(self, web_summary: dict = None) -> List[Fan]:
|
||||
if not web_summary:
|
||||
try:
|
||||
web_summary = await self.web.summary()
|
||||
@@ -215,7 +249,7 @@ class ePIC(BMMiner):
|
||||
fans.append(Fan())
|
||||
return fans
|
||||
|
||||
async def get_hashboards(
|
||||
async def _get_hashboards(
|
||||
self, web_summary: dict = None, web_hashrate: dict = None
|
||||
) -> List[HashBoard]:
|
||||
if not web_summary:
|
||||
@@ -232,7 +266,7 @@ class ePIC(BMMiner):
|
||||
HashBoard(slot=i, expected_chips=self.expected_chips)
|
||||
for i in range(self.expected_hashboards)
|
||||
]
|
||||
if web_summary["HBs"] != None:
|
||||
if web_summary["HBs"] is not None:
|
||||
for hb in web_summary["HBs"]:
|
||||
for hr in web_hashrate:
|
||||
if hr["Index"] == hb["Index"]:
|
||||
@@ -246,36 +280,10 @@ class ePIC(BMMiner):
|
||||
hb_list[hr["Index"]].temp = hb["Temperature"]
|
||||
return hb_list
|
||||
|
||||
async def is_mining(self, *args, **kwargs) -> Optional[bool]:
|
||||
async def _is_mining(self, *args, **kwargs) -> Optional[bool]:
|
||||
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:
|
||||
web_summary = await self.web.summary()
|
||||
if web_summary:
|
||||
@@ -286,7 +294,7 @@ class ePIC(BMMiner):
|
||||
pass
|
||||
return None
|
||||
|
||||
async def get_fault_light(self, web_summary: dict = None) -> bool:
|
||||
async def _get_fault_light(self, web_summary: dict = None) -> bool:
|
||||
if not web_summary:
|
||||
web_summary = await self.web.summary()
|
||||
if web_summary:
|
||||
@@ -297,16 +305,40 @@ class ePIC(BMMiner):
|
||||
pass
|
||||
return False
|
||||
|
||||
async def get_errors(self, web_summary: dict = None) -> List[MinerErrorData]:
|
||||
async def _get_errors(self, web_summary: dict = None) -> List[MinerErrorData]:
|
||||
if not web_summary:
|
||||
web_summary = await self.web.summary()
|
||||
errors = []
|
||||
if web_summary:
|
||||
try:
|
||||
error = web_summary["Status"]["Last Error"]
|
||||
if error != None:
|
||||
if error is not None:
|
||||
errors.append(X19Error(str(error)))
|
||||
return errors
|
||||
except KeyError:
|
||||
pass
|
||||
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_env_temp(self, *args, **kwargs) -> Optional[float]:
|
||||
pass
|
||||
|
||||
def _get_fan_psu(self, *args, **kwargs) -> Optional[int]:
|
||||
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
|
||||
|
||||
@@ -14,18 +14,67 @@
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
from typing import Optional
|
||||
from typing import List, Optional
|
||||
|
||||
from pyasic.data import HashBoard
|
||||
from pyasic.miners.backends import BMMiner
|
||||
from pyasic.miners.base import DataFunction, DataLocations, DataOptions, RPCAPICommand
|
||||
|
||||
HIVEON_DATA_LOC = DataLocations(
|
||||
**{
|
||||
str(DataOptions.MAC): DataFunction("get_mac"),
|
||||
str(DataOptions.API_VERSION): DataFunction(
|
||||
"_get_api_ver", [RPCAPICommand("api_version", "version")]
|
||||
),
|
||||
str(DataOptions.FW_VERSION): DataFunction(
|
||||
"_get_fw_ver", [RPCAPICommand("api_version", "version")]
|
||||
),
|
||||
str(DataOptions.HOSTNAME): DataFunction("_get_hostname"),
|
||||
str(DataOptions.HASHRATE): DataFunction(
|
||||
"_get_hashrate", [RPCAPICommand("api_summary", "summary")]
|
||||
),
|
||||
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
|
||||
"_get_expected_hashrate", [RPCAPICommand("api_stats", "stats")]
|
||||
),
|
||||
str(DataOptions.HASHBOARDS): DataFunction(
|
||||
"_get_hashboards", [RPCAPICommand("api_stats", "stats")]
|
||||
),
|
||||
str(DataOptions.ENVIRONMENT_TEMP): DataFunction(
|
||||
"_get_env_temp", [RPCAPICommand("api_stats", "stats")]
|
||||
),
|
||||
str(DataOptions.WATTAGE): DataFunction(
|
||||
"_get_wattage", [RPCAPICommand("api_stats", "stats")]
|
||||
),
|
||||
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 Hiveon(BMMiner):
|
||||
def __init__(self, ip: str, api_ver: str = "0.0.0") -> None:
|
||||
super().__init__(ip, api_ver)
|
||||
self.pwd = "admin"
|
||||
# static data
|
||||
self.api_type = "Hiveon"
|
||||
# data gathering locations
|
||||
self.data_locations = HIVEON_DATA_LOC
|
||||
|
||||
async def get_model(self) -> Optional[str]:
|
||||
if self.model is not None:
|
||||
return self.model + " (Hiveon)"
|
||||
return "? (Hiveon)"
|
||||
async def _get_hashboards(self, api_stats: dict = None) -> List[HashBoard]:
|
||||
pass
|
||||
|
||||
async def _get_wattage(self, api_stats: dict = None) -> Optional[int]:
|
||||
pass
|
||||
|
||||
async def _get_env_temp(self, api_stats: dict = None) -> Optional[float]:
|
||||
pass
|
||||
|
||||
403
pyasic/miners/backends/innosilicon.py
Normal file
403
pyasic/miners/backends/innosilicon.py
Normal file
@@ -0,0 +1,403 @@
|
||||
# ------------------------------------------------------------------------------
|
||||
# Copyright 2022 Upstream Data Inc -
|
||||
# -
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); -
|
||||
# you may not use this file except in compliance with the License. -
|
||||
# You may obtain a copy of the License at -
|
||||
# -
|
||||
# http://www.apache.org/licenses/LICENSE-2.0 -
|
||||
# -
|
||||
# Unless required by applicable law or agreed to in writing, software -
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, -
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -
|
||||
# See the License for the specific language governing permissions and -
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
from typing import List, Optional
|
||||
|
||||
from pyasic.config import MinerConfig
|
||||
from pyasic.data import Fan, HashBoard
|
||||
from pyasic.data.error_codes import MinerErrorData
|
||||
from pyasic.data.error_codes.innosilicon import InnosiliconError
|
||||
from pyasic.errors import APIError
|
||||
from pyasic.miners.backends import CGMiner
|
||||
from pyasic.miners.base import (
|
||||
DataFunction,
|
||||
DataLocations,
|
||||
DataOptions,
|
||||
RPCAPICommand,
|
||||
WebAPICommand,
|
||||
)
|
||||
from pyasic.web.innosilicon import InnosiliconWebAPI
|
||||
|
||||
INNOSILICON_DATA_LOC = DataLocations(
|
||||
**{
|
||||
str(DataOptions.MAC): DataFunction(
|
||||
"_get_mac",
|
||||
[
|
||||
WebAPICommand("web_get_all", "getAll"),
|
||||
WebAPICommand("web_overview", "overview"),
|
||||
],
|
||||
),
|
||||
str(DataOptions.API_VERSION): DataFunction(
|
||||
"_get_api_ver", [RPCAPICommand("api_version", "version")]
|
||||
),
|
||||
str(DataOptions.FW_VERSION): DataFunction(
|
||||
"_get_fw_ver", [RPCAPICommand("api_version", "version")]
|
||||
),
|
||||
str(DataOptions.HOSTNAME): DataFunction("_get_hostname"),
|
||||
str(DataOptions.HASHRATE): DataFunction(
|
||||
"_get_hashrate",
|
||||
[
|
||||
RPCAPICommand("api_summary", "summary"),
|
||||
WebAPICommand("web_get_all", "getAll"),
|
||||
],
|
||||
),
|
||||
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
|
||||
"_get_expected_hashrate",
|
||||
),
|
||||
str(DataOptions.HASHBOARDS): DataFunction(
|
||||
"_get_hashboards",
|
||||
[
|
||||
RPCAPICommand("api_stats", "stats"),
|
||||
WebAPICommand("web_get_all", "getAll"),
|
||||
],
|
||||
),
|
||||
str(DataOptions.ENVIRONMENT_TEMP): DataFunction("_get_env_temp"),
|
||||
str(DataOptions.WATTAGE): DataFunction(
|
||||
"_get_wattage",
|
||||
[
|
||||
WebAPICommand("web_get_all", "getAll"),
|
||||
RPCAPICommand("api_stats", "stats"),
|
||||
],
|
||||
),
|
||||
str(DataOptions.WATTAGE_LIMIT): DataFunction(
|
||||
"_get_wattage_limit",
|
||||
[
|
||||
WebAPICommand("web_get_all", "getAll"),
|
||||
],
|
||||
),
|
||||
str(DataOptions.FANS): DataFunction(
|
||||
"_get_fans",
|
||||
[
|
||||
WebAPICommand("web_get_all", "getAll"),
|
||||
],
|
||||
),
|
||||
str(DataOptions.FAN_PSU): DataFunction("_get_fan_psu"),
|
||||
str(DataOptions.ERRORS): DataFunction(
|
||||
"_get_errors",
|
||||
[
|
||||
WebAPICommand("web_get_error_detail", "getErrorDetail"),
|
||||
],
|
||||
),
|
||||
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 Innosilicon(CGMiner):
|
||||
def __init__(self, ip: str, api_ver: str = "0.0.0") -> None:
|
||||
super().__init__(ip, api_ver=api_ver)
|
||||
# interfaces
|
||||
self.web = InnosiliconWebAPI(ip)
|
||||
|
||||
# static data
|
||||
# data gathering locations
|
||||
self.data_locations = INNOSILICON_DATA_LOC
|
||||
# autotuning/shutdown support
|
||||
self.supports_shutdown = True
|
||||
|
||||
# data storage
|
||||
self.api_ver = api_ver
|
||||
|
||||
async def fault_light_on(self) -> bool:
|
||||
return False
|
||||
|
||||
async def fault_light_off(self) -> bool:
|
||||
return False
|
||||
|
||||
async def get_config(self) -> MinerConfig:
|
||||
# get pool data
|
||||
try:
|
||||
pools = await self.web.pools()
|
||||
except APIError:
|
||||
return self.config
|
||||
|
||||
self.config = MinerConfig.from_inno(pools)
|
||||
return self.config
|
||||
|
||||
async def reboot(self) -> bool:
|
||||
try:
|
||||
data = await self.web.reboot()
|
||||
except APIError:
|
||||
pass
|
||||
else:
|
||||
return data["success"]
|
||||
|
||||
async def restart_cgminer(self) -> bool:
|
||||
try:
|
||||
data = await self.web.restart_cgminer()
|
||||
except APIError:
|
||||
pass
|
||||
else:
|
||||
return data["success"]
|
||||
|
||||
async def restart_backend(self) -> bool:
|
||||
return await self.restart_cgminer()
|
||||
|
||||
async def stop_mining(self) -> bool:
|
||||
return False
|
||||
# data = await self.web.poweroff()
|
||||
# try:
|
||||
# return data["success"]
|
||||
# except KeyError:
|
||||
# return False
|
||||
|
||||
async def resume_mining(self) -> bool:
|
||||
return False
|
||||
# data = await self.web.restart_cgminer()
|
||||
# print(data)
|
||||
# try:
|
||||
# return data["success"]
|
||||
# except KeyError:
|
||||
# return False
|
||||
|
||||
async def send_config(self, config: MinerConfig, user_suffix: str = None) -> None:
|
||||
self.config = config
|
||||
await self.web.update_pools(config.as_inno(user_suffix=user_suffix))
|
||||
|
||||
##################################################
|
||||
### DATA GATHERING FUNCTIONS (get_{some_data}) ###
|
||||
##################################################
|
||||
|
||||
async def _get_mac(
|
||||
self, web_get_all: dict = None, web_overview: dict = None
|
||||
) -> Optional[str]:
|
||||
if web_get_all:
|
||||
web_get_all = web_get_all["all"]
|
||||
|
||||
if not web_get_all and not web_overview:
|
||||
try:
|
||||
web_overview = await self.web.overview()
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
if web_get_all:
|
||||
try:
|
||||
mac = web_get_all["mac"]
|
||||
return mac.upper()
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
if web_overview:
|
||||
try:
|
||||
mac = web_overview["version"]["ethaddr"]
|
||||
return mac.upper()
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
async def _get_hashrate(
|
||||
self, api_summary: dict = None, web_get_all: dict = None
|
||||
) -> Optional[float]:
|
||||
if web_get_all:
|
||||
web_get_all = web_get_all["all"]
|
||||
|
||||
if not api_summary and not web_get_all:
|
||||
try:
|
||||
api_summary = await self.api.summary()
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
if web_get_all:
|
||||
try:
|
||||
if "Hash Rate H" in web_get_all["total_hash"].keys():
|
||||
return round(
|
||||
float(web_get_all["total_hash"]["Hash Rate H"] / 1000000000000),
|
||||
2,
|
||||
)
|
||||
elif "Hash Rate" in web_get_all["total_hash"].keys():
|
||||
return round(
|
||||
float(web_get_all["total_hash"]["Hash Rate"] / 1000000), 5
|
||||
)
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
if api_summary:
|
||||
try:
|
||||
return round(float(api_summary["SUMMARY"][0]["MHS 1m"] / 1000000), 2)
|
||||
except (KeyError, IndexError):
|
||||
pass
|
||||
|
||||
async def _get_hashboards(
|
||||
self, api_stats: dict = None, web_get_all: dict = None
|
||||
) -> List[HashBoard]:
|
||||
if web_get_all:
|
||||
web_get_all = web_get_all["all"]
|
||||
|
||||
hashboards = [
|
||||
HashBoard(slot=i, expected_chips=self.expected_chips)
|
||||
for i in range(self.expected_hashboards)
|
||||
]
|
||||
|
||||
if not api_stats:
|
||||
try:
|
||||
api_stats = await self.api.stats()
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
if not web_get_all:
|
||||
try:
|
||||
web_get_all = await self.web.get_all()
|
||||
except APIError:
|
||||
pass
|
||||
else:
|
||||
web_get_all = web_get_all["all"]
|
||||
|
||||
if api_stats:
|
||||
if api_stats.get("STATS"):
|
||||
for board in api_stats["STATS"]:
|
||||
try:
|
||||
idx = board["Chain ID"]
|
||||
chips = board["Num active chips"]
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
hashboards[idx].chips = chips
|
||||
hashboards[idx].missing = False
|
||||
|
||||
if web_get_all:
|
||||
if web_get_all.get("chain"):
|
||||
for board in web_get_all["chain"]:
|
||||
idx = board.get("ASC")
|
||||
if idx is not None:
|
||||
temp = board.get("Temp min")
|
||||
if temp:
|
||||
hashboards[idx].temp = round(temp)
|
||||
|
||||
hashrate = board.get("Hash Rate H")
|
||||
if hashrate:
|
||||
hashboards[idx].hashrate = round(
|
||||
hashrate / 1000000000000, 2
|
||||
)
|
||||
|
||||
chip_temp = board.get("Temp max")
|
||||
if chip_temp:
|
||||
hashboards[idx].chip_temp = round(chip_temp)
|
||||
|
||||
return hashboards
|
||||
|
||||
async def _get_wattage(
|
||||
self, web_get_all: dict = None, api_stats: dict = None
|
||||
) -> Optional[int]:
|
||||
if web_get_all:
|
||||
web_get_all = web_get_all["all"]
|
||||
|
||||
if not web_get_all:
|
||||
try:
|
||||
web_get_all = await self.web.get_all()
|
||||
except APIError:
|
||||
pass
|
||||
else:
|
||||
web_get_all = web_get_all["all"]
|
||||
|
||||
if web_get_all:
|
||||
try:
|
||||
return web_get_all["power"]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
if not api_stats:
|
||||
try:
|
||||
api_stats = await self.api.stats()
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
if api_stats:
|
||||
if api_stats.get("STATS"):
|
||||
for board in api_stats["STATS"]:
|
||||
try:
|
||||
wattage = board["power"]
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
wattage = int(wattage)
|
||||
return wattage
|
||||
|
||||
async def _get_fans(self, web_get_all: dict = None) -> List[Fan]:
|
||||
if web_get_all:
|
||||
web_get_all = web_get_all["all"]
|
||||
|
||||
if not web_get_all:
|
||||
try:
|
||||
web_get_all = await self.web.get_all()
|
||||
except APIError:
|
||||
pass
|
||||
else:
|
||||
web_get_all = web_get_all["all"]
|
||||
|
||||
fans = [Fan() for _ in range(self.expected_fans)]
|
||||
if web_get_all:
|
||||
try:
|
||||
spd = web_get_all["fansSpeed"]
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
round((int(spd) * 6000) / 100)
|
||||
for i in range(self.expected_fans):
|
||||
fans[i].speed = spd
|
||||
|
||||
return fans
|
||||
|
||||
async def _get_errors(
|
||||
self, web_get_error_detail: dict = None
|
||||
) -> List[MinerErrorData]:
|
||||
errors = []
|
||||
if not web_get_error_detail:
|
||||
try:
|
||||
web_get_error_detail = await self.web.get_error_detail()
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
if web_get_error_detail:
|
||||
try:
|
||||
# only 1 error?
|
||||
# TODO: check if this should be a loop, can't remember.
|
||||
err = web_get_error_detail["code"]
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
err = int(err)
|
||||
if not err == 0:
|
||||
errors.append(InnosiliconError(error_code=err))
|
||||
return errors
|
||||
|
||||
async def _get_wattage_limit(self, web_get_all: dict = None) -> Optional[int]:
|
||||
if web_get_all:
|
||||
web_get_all = web_get_all["all"]
|
||||
|
||||
if not web_get_all:
|
||||
try:
|
||||
web_get_all = await self.web.get_all()
|
||||
except APIError:
|
||||
pass
|
||||
else:
|
||||
web_get_all = web_get_all["all"]
|
||||
|
||||
if web_get_all:
|
||||
try:
|
||||
level = web_get_all["running_mode"]["level"]
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
# this is very possibly not correct.
|
||||
level = int(level)
|
||||
limit = 1250 + (250 * level)
|
||||
return limit
|
||||
|
||||
async def _get_expected_hashrate(self) -> Optional[float]:
|
||||
pass
|
||||
@@ -13,43 +13,56 @@
|
||||
# See the License for the specific language governing permissions and -
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
import asyncio
|
||||
import logging
|
||||
from collections import namedtuple
|
||||
from typing import List, Optional, Tuple, Union
|
||||
|
||||
import toml
|
||||
|
||||
from pyasic.API.bosminer import BOSMinerAPI
|
||||
from pyasic.API.luxminer import LUXMinerAPI
|
||||
from pyasic.config import MinerConfig
|
||||
from pyasic.data import Fan, HashBoard
|
||||
from pyasic.data.error_codes import BraiinsOSError, MinerErrorData
|
||||
from pyasic.data.error_codes import MinerErrorData
|
||||
from pyasic.errors import APIError
|
||||
from pyasic.miners.base import BaseMiner
|
||||
from pyasic.web.bosminer import BOSMinerWebAPI
|
||||
from pyasic.miners.base import (
|
||||
BaseMiner,
|
||||
DataFunction,
|
||||
DataLocations,
|
||||
DataOptions,
|
||||
RPCAPICommand,
|
||||
)
|
||||
|
||||
LUXMINER_DATA_LOC = {
|
||||
"mac": {"cmd": "get_mac", "kwargs": {"api_config": {"api": "config"}}},
|
||||
"model": {"cmd": "get_model", "kwargs": {}},
|
||||
"api_ver": {"cmd": "get_api_ver", "kwargs": {}},
|
||||
"fw_ver": {"cmd": "get_fw_ver", "kwargs": {}},
|
||||
"hostname": {"cmd": "get_hostname", "kwargs": {}},
|
||||
"hashrate": {"cmd": "get_hashrate", "kwargs": {}},
|
||||
"expected_hashrate": {"cmd": "get_expected_hashrate", "kwargs": {}},
|
||||
"hashboards": {"cmd": "get_hashboards", "kwargs": {}},
|
||||
"wattage": {"cmd": "get_wattage", "kwargs": {}},
|
||||
"wattage_limit": {"cmd": "get_wattage_limit", "kwargs": {}},
|
||||
"fans": {"cmd": "get_fans", "kwargs": {}},
|
||||
"fan_psu": {"cmd": "get_fan_psu", "kwargs": {}},
|
||||
"env_temp": {"cmd": "get_env_temp", "kwargs": {}},
|
||||
"errors": {"cmd": "get_errors", "kwargs": {}},
|
||||
"fault_light": {"cmd": "get_fault_light", "kwargs": {}},
|
||||
"pools": {"cmd": "get_pools", "kwargs": {}},
|
||||
"is_mining": {"cmd": "is_mining", "kwargs": {}},
|
||||
"uptime": {"cmd": "get_uptime", "kwargs": {"api_stats": {"api": "stats"}}},
|
||||
"config": {"cmd": "get_config", "kwargs": {}},
|
||||
}
|
||||
LUXMINER_DATA_LOC = DataLocations(
|
||||
**{
|
||||
str(DataOptions.MAC): DataFunction(
|
||||
"_get_mac", [RPCAPICommand("api_config", "config")]
|
||||
),
|
||||
str(DataOptions.API_VERSION): DataFunction("_get_api_ver"),
|
||||
str(DataOptions.FW_VERSION): DataFunction("_get_fw_ver"),
|
||||
str(DataOptions.HOSTNAME): DataFunction("_get_hostname"),
|
||||
str(DataOptions.HASHRATE): DataFunction(
|
||||
"_get_hashrate", [RPCAPICommand("api_summary", "summary")]
|
||||
),
|
||||
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
|
||||
"_get_expected_hashrate", [RPCAPICommand("api_stats", "stats")]
|
||||
),
|
||||
str(DataOptions.HASHBOARDS): DataFunction(
|
||||
"_get_hashboards", [RPCAPICommand("api_stats", "stats")]
|
||||
),
|
||||
str(DataOptions.ENVIRONMENT_TEMP): DataFunction("_get_env_temp"),
|
||||
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):
|
||||
@@ -61,6 +74,7 @@ class LUXMiner(BaseMiner):
|
||||
|
||||
# static data
|
||||
self.api_type = "LUXMiner"
|
||||
self.fw_str = "LuxOS"
|
||||
# data gathering locations
|
||||
self.data_locations = LUXMINER_DATA_LOC
|
||||
# autotuning/shutdown support
|
||||
@@ -85,7 +99,6 @@ class LUXMiner(BaseMiner):
|
||||
return
|
||||
|
||||
async def fault_light_on(self) -> bool:
|
||||
"""Sends command to turn on fault light on the miner."""
|
||||
try:
|
||||
session_id = await self._get_session()
|
||||
if session_id:
|
||||
@@ -96,7 +109,6 @@ class LUXMiner(BaseMiner):
|
||||
return False
|
||||
|
||||
async def fault_light_off(self) -> bool:
|
||||
"""Sends command to turn off fault light on the miner."""
|
||||
try:
|
||||
session_id = await self._get_session()
|
||||
if session_id:
|
||||
@@ -107,11 +119,9 @@ class LUXMiner(BaseMiner):
|
||||
return False
|
||||
|
||||
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()
|
||||
|
||||
async def restart_luxminer(self) -> bool:
|
||||
"""Restart luxminer hashing process."""
|
||||
try:
|
||||
session_id = await self._get_session()
|
||||
if session_id:
|
||||
@@ -141,7 +151,6 @@ class LUXMiner(BaseMiner):
|
||||
pass
|
||||
|
||||
async def reboot(self) -> bool:
|
||||
"""Reboots power to the physical miner."""
|
||||
try:
|
||||
session_id = await self._get_session()
|
||||
if session_id:
|
||||
@@ -164,7 +173,7 @@ class LUXMiner(BaseMiner):
|
||||
### DATA GATHERING FUNCTIONS (get_{some_data}) ###
|
||||
##################################################
|
||||
|
||||
async def get_mac(self, api_config: dict = None) -> Optional[str]:
|
||||
async def _get_mac(self, api_config: dict = None) -> Optional[str]:
|
||||
mac = None
|
||||
if not api_config:
|
||||
try:
|
||||
@@ -180,24 +189,19 @@ class LUXMiner(BaseMiner):
|
||||
|
||||
return mac
|
||||
|
||||
async def get_model(self) -> Optional[str]:
|
||||
if self.model is not None:
|
||||
return self.model + " (LuxOS)"
|
||||
return "? (LuxOS)"
|
||||
|
||||
async def get_version(self) -> Tuple[Optional[str], Optional[str]]:
|
||||
pass
|
||||
|
||||
async def get_api_ver(self) -> Optional[str]:
|
||||
async def _get_api_ver(self) -> Optional[str]:
|
||||
pass
|
||||
|
||||
async def get_fw_ver(self) -> Optional[str]:
|
||||
async def _get_fw_ver(self) -> Optional[str]:
|
||||
pass
|
||||
|
||||
async def get_hostname(self) -> Union[str, None]:
|
||||
async def _get_hostname(self) -> Union[str, None]:
|
||||
pass
|
||||
|
||||
async def get_hashrate(self, api_summary: dict = None) -> Optional[float]:
|
||||
async def _get_hashrate(self, api_summary: dict = None) -> Optional[float]:
|
||||
if not api_summary:
|
||||
try:
|
||||
api_summary = await self.api.summary()
|
||||
@@ -207,10 +211,10 @@ class LUXMiner(BaseMiner):
|
||||
if api_summary:
|
||||
try:
|
||||
return round(float(api_summary["SUMMARY"][0]["GHS 5s"] / 1000), 2)
|
||||
except (IndexError, KeyError, ValueError, TypeError):
|
||||
except (LookupError, ValueError, TypeError):
|
||||
pass
|
||||
|
||||
async def get_hashboards(self, api_stats: dict = None) -> List[HashBoard]:
|
||||
async def _get_hashboards(self, api_stats: dict = None) -> List[HashBoard]:
|
||||
hashboards = []
|
||||
|
||||
if not api_stats:
|
||||
@@ -259,15 +263,15 @@ class LUXMiner(BaseMiner):
|
||||
if (not chips) or (not chips > 0):
|
||||
hashboard.missing = True
|
||||
hashboards.append(hashboard)
|
||||
except (IndexError, KeyError, ValueError, TypeError):
|
||||
except (LookupError, ValueError, TypeError):
|
||||
pass
|
||||
|
||||
return hashboards
|
||||
|
||||
async def get_env_temp(self) -> Optional[float]:
|
||||
async def _get_env_temp(self) -> Optional[float]:
|
||||
return None
|
||||
|
||||
async def get_wattage(self, api_power: dict) -> Optional[int]:
|
||||
async def _get_wattage(self, api_power: dict) -> Optional[int]:
|
||||
if not api_power:
|
||||
try:
|
||||
api_power = await self.api.power()
|
||||
@@ -277,13 +281,13 @@ class LUXMiner(BaseMiner):
|
||||
if api_power:
|
||||
try:
|
||||
return api_power["POWER"][0]["Watts"]
|
||||
except (IndexError, KeyError, ValueError, TypeError):
|
||||
except (LookupError, ValueError, TypeError):
|
||||
pass
|
||||
|
||||
async def get_wattage_limit(self) -> Optional[int]:
|
||||
async def _get_wattage_limit(self) -> Optional[int]:
|
||||
return None
|
||||
|
||||
async def get_fans(self, api_fans: dict = None) -> List[Fan]:
|
||||
async def _get_fans(self, api_fans: dict = None) -> List[Fan]:
|
||||
if not api_fans:
|
||||
try:
|
||||
api_fans = await self.api.fans()
|
||||
@@ -293,73 +297,23 @@ class LUXMiner(BaseMiner):
|
||||
fans = []
|
||||
|
||||
if api_fans:
|
||||
for fan in range(self.fan_count):
|
||||
for fan in range(self.expected_fans):
|
||||
try:
|
||||
fans.append(Fan(api_fans["FANS"][0]["RPM"]))
|
||||
except (IndexError, KeyError, ValueError, TypeError):
|
||||
fans.append(Fan(api_fans["FANS"][fan]["RPM"]))
|
||||
except (LookupError, ValueError, TypeError):
|
||||
fans.append(Fan())
|
||||
return fans
|
||||
|
||||
async def get_fan_psu(self) -> Optional[int]:
|
||||
async def _get_fan_psu(self) -> Optional[int]:
|
||||
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
|
||||
|
||||
async def get_fault_light(self) -> bool:
|
||||
async def _get_fault_light(self) -> bool:
|
||||
pass
|
||||
|
||||
async def get_expected_hashrate(self, api_stats: dict = None) -> Optional[float]:
|
||||
async def _get_expected_hashrate(self, api_stats: dict = None) -> Optional[float]:
|
||||
if not api_stats:
|
||||
try:
|
||||
api_stats = await self.api.stats()
|
||||
@@ -379,13 +333,13 @@ class LUXMiner(BaseMiner):
|
||||
return round(expected_rate / 1000000, 2)
|
||||
else:
|
||||
return round(expected_rate, 2)
|
||||
except (KeyError, IndexError):
|
||||
except LookupError:
|
||||
pass
|
||||
|
||||
async def is_mining(self) -> Optional[bool]:
|
||||
async def _is_mining(self) -> Optional[bool]:
|
||||
pass
|
||||
|
||||
async def get_uptime(self, api_stats: dict = None) -> Optional[int]:
|
||||
async def _get_uptime(self, api_stats: dict = None) -> Optional[int]:
|
||||
if not api_stats:
|
||||
try:
|
||||
api_stats = await self.api.stats()
|
||||
|
||||
@@ -16,38 +16,60 @@
|
||||
|
||||
from typing import Optional
|
||||
|
||||
from pyasic import MinerConfig
|
||||
from pyasic.errors import APIError
|
||||
from pyasic.logger import logger
|
||||
from pyasic.miners.backends.bmminer import BMMiner
|
||||
from pyasic.miners.base import (
|
||||
DataFunction,
|
||||
DataLocations,
|
||||
DataOptions,
|
||||
RPCAPICommand,
|
||||
WebAPICommand,
|
||||
)
|
||||
from pyasic.web.vnish import VNishWebAPI
|
||||
|
||||
VNISH_DATA_LOC = {
|
||||
"mac": {"cmd": "get_mac", "kwargs": {"web_summary": {"web": "summary"}}},
|
||||
"model": {"cmd": "get_model", "kwargs": {}},
|
||||
"api_ver": {"cmd": "get_api_ver", "kwargs": {"api_version": {"api": "version"}}},
|
||||
"fw_ver": {"cmd": "get_fw_ver", "kwargs": {"web_summary": {"web": "summary"}}},
|
||||
"hostname": {"cmd": "get_hostname", "kwargs": {"web_summary": {"web": "summary"}}},
|
||||
"hashrate": {"cmd": "get_hashrate", "kwargs": {"api_summary": {"api": "summary"}}},
|
||||
"expected_hashrate": {
|
||||
"cmd": "get_expected_hashrate",
|
||||
"kwargs": {"api_stats": {"api": "stats"}},
|
||||
},
|
||||
"hashboards": {"cmd": "get_hashboards", "kwargs": {"api_stats": {"api": "stats"}}},
|
||||
"env_temp": {"cmd": "get_env_temp", "kwargs": {}},
|
||||
"wattage": {"cmd": "get_wattage", "kwargs": {"web_summary": {"web": "summary"}}},
|
||||
"wattage_limit": {
|
||||
"cmd": "get_wattage_limit",
|
||||
"kwargs": {"web_settings": {"web": "settings"}},
|
||||
},
|
||||
"fans": {"cmd": "get_fans", "kwargs": {"api_stats": {"api": "stats"}}},
|
||||
"fan_psu": {"cmd": "get_fan_psu", "kwargs": {}},
|
||||
"errors": {"cmd": "get_errors", "kwargs": {}},
|
||||
"fault_light": {"cmd": "get_fault_light", "kwargs": {}},
|
||||
"pools": {"cmd": "get_pools", "kwargs": {"api_pools": {"api": "pools"}}},
|
||||
"is_mining": {"cmd": "is_mining", "kwargs": {}},
|
||||
"uptime": {"cmd": "get_uptime", "kwargs": {}},
|
||||
"config": {"cmd": "get_config", "kwargs": {}},
|
||||
}
|
||||
VNISH_DATA_LOC = DataLocations(
|
||||
**{
|
||||
str(DataOptions.MAC): DataFunction(
|
||||
"_get_mac", [WebAPICommand("web_summary", "summary")]
|
||||
),
|
||||
str(DataOptions.API_VERSION): DataFunction(
|
||||
"_get_api_ver", [RPCAPICommand("api_version", "version")]
|
||||
),
|
||||
str(DataOptions.FW_VERSION): DataFunction(
|
||||
"_get_fw_ver", [WebAPICommand("web_summary", "summary")]
|
||||
),
|
||||
str(DataOptions.HOSTNAME): DataFunction(
|
||||
"_get_hostname", [WebAPICommand("web_summary", "summary")]
|
||||
),
|
||||
str(DataOptions.HASHRATE): DataFunction(
|
||||
"_get_hashrate", [RPCAPICommand("api_summary", "summary")]
|
||||
),
|
||||
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
|
||||
"_get_expected_hashrate", [RPCAPICommand("api_stats", "stats")]
|
||||
),
|
||||
str(DataOptions.HASHBOARDS): DataFunction(
|
||||
"_get_hashboards", [RPCAPICommand("api_stats", "stats")]
|
||||
),
|
||||
str(DataOptions.ENVIRONMENT_TEMP): DataFunction("_get_env_temp"),
|
||||
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):
|
||||
@@ -58,14 +80,10 @@ class VNish(BMMiner):
|
||||
|
||||
# static data
|
||||
self.api_type = "VNish"
|
||||
self.fw_str = "VNish"
|
||||
# data gathering locations
|
||||
self.data_locations = VNISH_DATA_LOC
|
||||
|
||||
async def get_model(self) -> Optional[str]:
|
||||
if self.model is not None:
|
||||
return self.model + " (VNish)"
|
||||
return "? (VNish)"
|
||||
|
||||
async def restart_backend(self) -> bool:
|
||||
data = await self.web.restart_vnish()
|
||||
if data:
|
||||
@@ -102,7 +120,7 @@ class VNish(BMMiner):
|
||||
pass
|
||||
return False
|
||||
|
||||
async def get_mac(self, web_summary: dict = None) -> str:
|
||||
async def _get_mac(self, web_summary: dict = None) -> str:
|
||||
if not web_summary:
|
||||
web_info = await self.web.info()
|
||||
|
||||
@@ -120,7 +138,7 @@ class VNish(BMMiner):
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
async def get_hostname(self, web_summary: dict = None) -> str:
|
||||
async def _get_hostname(self, web_summary: dict = None) -> str:
|
||||
if not web_summary:
|
||||
web_info = await self.web.info()
|
||||
|
||||
@@ -138,7 +156,7 @@ class VNish(BMMiner):
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
async def get_wattage(self, web_summary: dict = None) -> Optional[int]:
|
||||
async def _get_wattage(self, web_summary: dict = None) -> Optional[int]:
|
||||
if not web_summary:
|
||||
web_summary = await self.web.summary()
|
||||
|
||||
@@ -150,7 +168,7 @@ class VNish(BMMiner):
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
async def get_hashrate(self, api_summary: dict = None) -> Optional[float]:
|
||||
async def _get_hashrate(self, api_summary: dict = None) -> Optional[float]:
|
||||
# get hr from API
|
||||
if not api_summary:
|
||||
try:
|
||||
@@ -163,11 +181,11 @@ class VNish(BMMiner):
|
||||
return round(
|
||||
float(float(api_summary["SUMMARY"][0]["GHS 5s"]) / 1000), 2
|
||||
)
|
||||
except (IndexError, KeyError, ValueError, TypeError) as e:
|
||||
except (LookupError, ValueError, TypeError) as e:
|
||||
logger.error(e)
|
||||
pass
|
||||
|
||||
async def get_wattage_limit(self, web_settings: dict = None) -> Optional[int]:
|
||||
async def _get_wattage_limit(self, web_settings: dict = None) -> Optional[int]:
|
||||
if not web_settings:
|
||||
web_settings = await self.web.summary()
|
||||
|
||||
@@ -180,7 +198,7 @@ class VNish(BMMiner):
|
||||
except (KeyError, TypeError):
|
||||
pass
|
||||
|
||||
async def get_fw_ver(self, web_summary: dict = None) -> Optional[str]:
|
||||
async def _get_fw_ver(self, web_summary: dict = None) -> Optional[str]:
|
||||
if not web_summary:
|
||||
web_summary = await self.web.summary()
|
||||
|
||||
@@ -192,8 +210,16 @@ class VNish(BMMiner):
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
async def is_mining(self, *args, **kwargs) -> Optional[bool]:
|
||||
async def _is_mining(self, *args, **kwargs) -> Optional[bool]:
|
||||
return None
|
||||
|
||||
async def get_uptime(self, *args, **kwargs) -> Optional[int]:
|
||||
async def _get_uptime(self, *args, **kwargs) -> Optional[int]:
|
||||
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,16 +17,82 @@ import asyncio
|
||||
import ipaddress
|
||||
import logging
|
||||
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
|
||||
|
||||
from pyasic.config import MinerConfig
|
||||
from pyasic.data import Fan, HashBoard, MinerData
|
||||
from pyasic.data.error_codes import MinerErrorData
|
||||
from pyasic.errors import APIError
|
||||
from pyasic.logger import logger
|
||||
|
||||
|
||||
class DataOptions(Enum):
|
||||
MAC = "mac"
|
||||
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):
|
||||
def __init__(self, ip: str, *args, **kwargs) -> None:
|
||||
# interfaces
|
||||
@@ -40,13 +106,14 @@ class BaseMiner(ABC):
|
||||
self.api_type = None
|
||||
# type
|
||||
self.make = None
|
||||
self.model = None
|
||||
self.raw_model = None
|
||||
self.fw_str = None
|
||||
# physical attributes
|
||||
self.expected_hashboards = 3
|
||||
self.expected_chips = 0
|
||||
self.fan_count = 2
|
||||
self.expected_fans = 2
|
||||
# data gathering locations
|
||||
self.data_locations = None
|
||||
self.data_locations: DataLocations = None
|
||||
# autotuning/shutdown support
|
||||
self.supports_autotuning = False
|
||||
self.supports_shutdown = False
|
||||
@@ -74,6 +141,13 @@ class BaseMiner(ABC):
|
||||
def __eq__(self, other):
|
||||
return ipaddress.ip_address(self.ip) == ipaddress.ip_address(other.ip)
|
||||
|
||||
@property
|
||||
def model(self):
|
||||
model_data = [self.raw_model if self.raw_model is not None else "Unknown"]
|
||||
if self.fw_str is not None:
|
||||
model_data.append(f"({self.fw_str})")
|
||||
return " ".join(model_data)
|
||||
|
||||
@property
|
||||
def pwd(self): # noqa - Skip PyCharm inspection
|
||||
data = []
|
||||
@@ -243,14 +317,13 @@ class BaseMiner(ABC):
|
||||
### DATA GATHERING FUNCTIONS (get_{some_data}) ###
|
||||
##################################################
|
||||
|
||||
@abstractmethod
|
||||
async def get_mac(self, *args, **kwargs) -> Optional[str]:
|
||||
async def get_mac(self) -> Optional[str]:
|
||||
"""Get the MAC address of the miner and return it as a string.
|
||||
|
||||
Returns:
|
||||
A string representing the MAC address of the miner.
|
||||
"""
|
||||
pass
|
||||
return await self._get_mac()
|
||||
|
||||
async def get_model(self) -> Optional[str]:
|
||||
"""Get the model of the miner and return it as a string.
|
||||
@@ -260,182 +333,228 @@ class BaseMiner(ABC):
|
||||
"""
|
||||
return self.model
|
||||
|
||||
@abstractmethod
|
||||
async def get_api_ver(self, *args, **kwargs) -> Optional[str]:
|
||||
async def get_api_ver(self) -> Optional[str]:
|
||||
"""Get the API version of the miner and is as a string.
|
||||
|
||||
Returns:
|
||||
API version as a string.
|
||||
"""
|
||||
pass
|
||||
return await self._get_api_ver()
|
||||
|
||||
@abstractmethod
|
||||
async def get_fw_ver(self, *args, **kwargs) -> Optional[str]:
|
||||
async def get_fw_ver(self) -> Optional[str]:
|
||||
"""Get the firmware version of the miner and is as a string.
|
||||
|
||||
Returns:
|
||||
Firmware version as a string.
|
||||
"""
|
||||
pass
|
||||
return await self._get_fw_ver()
|
||||
|
||||
@abstractmethod
|
||||
async def get_version(self, *args, **kwargs) -> Tuple[Optional[str], Optional[str]]:
|
||||
async def get_version(self) -> Tuple[Optional[str], Optional[str]]:
|
||||
"""Get the API version and firmware version of the miner and return them as strings.
|
||||
|
||||
Returns:
|
||||
A tuple of (API version, firmware version) as strings.
|
||||
"""
|
||||
pass
|
||||
api_ver = await self.get_api_ver()
|
||||
fw_ver = await self.get_fw_ver()
|
||||
return api_ver, fw_ver
|
||||
|
||||
@abstractmethod
|
||||
async def get_hostname(self, *args, **kwargs) -> Optional[str]:
|
||||
async def get_hostname(self) -> Optional[str]:
|
||||
"""Get the hostname of the miner and return it as a string.
|
||||
|
||||
Returns:
|
||||
A string representing the hostname of the miner.
|
||||
"""
|
||||
pass
|
||||
return await self._get_hostname()
|
||||
|
||||
@abstractmethod
|
||||
async def get_hashrate(self, *args, **kwargs) -> Optional[float]:
|
||||
async def get_hashrate(self) -> Optional[float]:
|
||||
"""Get the hashrate of the miner and return it as a float in TH/s.
|
||||
|
||||
Returns:
|
||||
Hashrate of the miner in TH/s as a float.
|
||||
"""
|
||||
pass
|
||||
return await self._get_hashrate()
|
||||
|
||||
@abstractmethod
|
||||
async def get_hashboards(self, *args, **kwargs) -> List[HashBoard]:
|
||||
async def get_hashboards(self) -> List[HashBoard]:
|
||||
"""Get hashboard data from the miner in the form of [`HashBoard`][pyasic.data.HashBoard].
|
||||
|
||||
Returns:
|
||||
A [`HashBoard`][pyasic.data.HashBoard] instance containing hashboard data from the miner.
|
||||
"""
|
||||
pass
|
||||
return await self._get_hashboards()
|
||||
|
||||
@abstractmethod
|
||||
async def get_env_temp(self, *args, **kwargs) -> Optional[float]:
|
||||
async def get_env_temp(self) -> Optional[float]:
|
||||
"""Get environment temp from the miner as a float.
|
||||
|
||||
Returns:
|
||||
Environment temp of the miner as a float.
|
||||
"""
|
||||
pass
|
||||
return await self._get_env_temp()
|
||||
|
||||
@abstractmethod
|
||||
async def get_wattage(self, *args, **kwargs) -> Optional[int]:
|
||||
async def get_wattage(self) -> Optional[int]:
|
||||
"""Get wattage from the miner as an int.
|
||||
|
||||
Returns:
|
||||
Wattage of the miner as an int.
|
||||
"""
|
||||
pass
|
||||
return await self._get_wattage()
|
||||
|
||||
@abstractmethod
|
||||
async def get_wattage_limit(self, *args, **kwargs) -> Optional[int]:
|
||||
async def get_wattage_limit(self) -> Optional[int]:
|
||||
"""Get wattage limit from the miner as an int.
|
||||
|
||||
Returns:
|
||||
Wattage limit of the miner as an int.
|
||||
"""
|
||||
pass
|
||||
return await self._get_wattage_limit()
|
||||
|
||||
@abstractmethod
|
||||
async def get_fans(self, *args, **kwargs) -> List[Fan]:
|
||||
async def get_fans(self) -> List[Fan]:
|
||||
"""Get fan data from the miner in the form [fan_1, fan_2, fan_3, fan_4].
|
||||
|
||||
Returns:
|
||||
A list of fan data.
|
||||
"""
|
||||
pass
|
||||
return await self._get_fans()
|
||||
|
||||
@abstractmethod
|
||||
async def get_fan_psu(self, *args, **kwargs) -> Optional[int]:
|
||||
async def get_fan_psu(self) -> Optional[int]:
|
||||
"""Get PSU fan speed from the miner.
|
||||
|
||||
Returns:
|
||||
PSU fan speed.
|
||||
"""
|
||||
pass
|
||||
return await self._get_fan_psu()
|
||||
|
||||
@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
|
||||
async def get_errors(self, *args, **kwargs) -> List[MinerErrorData]:
|
||||
async def get_errors(self) -> List[MinerErrorData]:
|
||||
"""Get a list of the errors the miner is experiencing.
|
||||
|
||||
Returns:
|
||||
A list of error classes representing different errors.
|
||||
"""
|
||||
pass
|
||||
return await self._get_errors()
|
||||
|
||||
@abstractmethod
|
||||
async def get_fault_light(self, *args, **kwargs) -> bool:
|
||||
async def get_fault_light(self) -> bool:
|
||||
"""Check the status of the fault light and return on or off as a boolean.
|
||||
|
||||
Returns:
|
||||
A boolean value where `True` represents on and `False` represents off.
|
||||
"""
|
||||
pass
|
||||
return await self._get_fault_light()
|
||||
|
||||
@abstractmethod
|
||||
async def get_expected_hashrate(self, *args, **kwargs) -> Optional[float]:
|
||||
async def get_expected_hashrate(self) -> Optional[float]:
|
||||
"""Get the nominal hashrate from factory if available.
|
||||
|
||||
Returns:
|
||||
A float value of nominal hashrate in TH/s.
|
||||
"""
|
||||
pass
|
||||
return await self._get_expected_hashrate()
|
||||
|
||||
@abstractmethod
|
||||
async def is_mining(self, *args, **kwargs) -> Optional[bool]:
|
||||
async def is_mining(self) -> Optional[bool]:
|
||||
"""Check whether the miner is mining.
|
||||
|
||||
Returns:
|
||||
A boolean value representing if the miner is mining.
|
||||
"""
|
||||
pass
|
||||
return await self._is_mining()
|
||||
|
||||
@abstractmethod
|
||||
async def get_uptime(self, *args, **kwargs) -> Optional[int]:
|
||||
async def get_uptime(self) -> Optional[int]:
|
||||
"""Get the uptime of the miner in seconds.
|
||||
|
||||
Returns:
|
||||
The uptime of the miner in seconds.
|
||||
"""
|
||||
return await self._get_uptime()
|
||||
|
||||
@abstractmethod
|
||||
async def _get_mac(self, *args, **kwargs) -> Optional[str]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def _get_api_ver(self, *args, **kwargs) -> Optional[str]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def _get_fw_ver(self, *args, **kwargs) -> Optional[str]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def _get_hostname(self, *args, **kwargs) -> Optional[str]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def _get_hashrate(self, *args, **kwargs) -> Optional[float]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def _get_hashboards(self, *args, **kwargs) -> List[HashBoard]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def _get_env_temp(self, *args, **kwargs) -> Optional[float]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def _get_wattage(self, *args, **kwargs) -> Optional[int]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def _get_wattage_limit(self, *args, **kwargs) -> Optional[int]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def _get_fans(self, *args, **kwargs) -> List[Fan]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def _get_fan_psu(self, *args, **kwargs) -> Optional[int]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def _get_errors(self, *args, **kwargs) -> List[MinerErrorData]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def _get_fault_light(self, *args, **kwargs) -> bool:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def _get_expected_hashrate(self, *args, **kwargs) -> Optional[float]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def _is_mining(self, *args, **kwargs) -> Optional[bool]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def _get_uptime(self, *args, **kwargs) -> Optional[int]:
|
||||
pass
|
||||
|
||||
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:
|
||||
if include is None:
|
||||
if include is not None:
|
||||
include = [str(i) for i in include]
|
||||
else:
|
||||
# everything
|
||||
include = list(self.data_locations.keys())
|
||||
include = [str(enum_value.value) for enum_value in DataOptions]
|
||||
|
||||
if exclude is not None:
|
||||
for item in exclude:
|
||||
if item in include:
|
||||
include.remove(item)
|
||||
if str(item) in include:
|
||||
include.remove(str(item))
|
||||
|
||||
api_multicommand = set()
|
||||
web_multicommand = []
|
||||
for data_name in include:
|
||||
try:
|
||||
fn_args = self.data_locations[data_name]["kwargs"]
|
||||
for arg_name in fn_args:
|
||||
if fn_args[arg_name].get("api"):
|
||||
api_multicommand.add(fn_args[arg_name]["api"])
|
||||
if fn_args[arg_name].get("web"):
|
||||
if not fn_args[arg_name]["web"] in web_multicommand:
|
||||
web_multicommand.append(fn_args[arg_name]["web"])
|
||||
fn_args = getattr(self.data_locations, data_name).kwargs
|
||||
for arg in fn_args:
|
||||
if isinstance(arg, RPCAPICommand):
|
||||
api_multicommand.add(arg.cmd)
|
||||
if isinstance(arg, WebAPICommand):
|
||||
if arg.cmd not in web_multicommand:
|
||||
web_multicommand.append(arg.cmd)
|
||||
except KeyError as e:
|
||||
logger.error(e, data_name)
|
||||
continue
|
||||
@@ -465,37 +584,40 @@ class BaseMiner(ABC):
|
||||
|
||||
for data_name in include:
|
||||
try:
|
||||
fn_args = self.data_locations[data_name]["kwargs"]
|
||||
args_to_send = {k: None for k in fn_args}
|
||||
for arg_name in fn_args:
|
||||
fn_args = getattr(self.data_locations, data_name).kwargs
|
||||
args_to_send = {k.name: None for k in fn_args}
|
||||
for arg in fn_args:
|
||||
try:
|
||||
if fn_args[arg_name].get("api"):
|
||||
if isinstance(arg, RPCAPICommand):
|
||||
if api_command_data.get("multicommand"):
|
||||
args_to_send[arg_name] = api_command_data[
|
||||
fn_args[arg_name]["api"]
|
||||
][0]
|
||||
args_to_send[arg.name] = api_command_data[arg.cmd][0]
|
||||
else:
|
||||
args_to_send[arg_name] = api_command_data
|
||||
if fn_args[arg_name].get("web"):
|
||||
args_to_send[arg.name] = api_command_data
|
||||
if isinstance(arg, WebAPICommand):
|
||||
if web_command_data is not None:
|
||||
if web_command_data.get("multicommand"):
|
||||
args_to_send[arg_name] = web_command_data[
|
||||
fn_args[arg_name]["web"]
|
||||
]
|
||||
args_to_send[arg.name] = web_command_data[arg.cmd]
|
||||
else:
|
||||
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:
|
||||
args_to_send[arg_name] = None
|
||||
args_to_send[arg.name] = None
|
||||
except LookupError:
|
||||
continue
|
||||
|
||||
function = getattr(self, self.data_locations[data_name]["cmd"])
|
||||
miner_data[data_name] = await function(**args_to_send)
|
||||
try:
|
||||
function = getattr(self, getattr(self.data_locations, data_name).cmd)
|
||||
miner_data[data_name] = await function(**args_to_send)
|
||||
except Exception as e:
|
||||
raise APIError(
|
||||
f"Failed to call {data_name} on {self} while getting data."
|
||||
) from e
|
||||
return miner_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:
|
||||
"""Get data from the miner in the form of [`MinerData`][pyasic.data.MinerData].
|
||||
|
||||
@@ -510,6 +632,7 @@ class BaseMiner(ABC):
|
||||
data = MinerData(
|
||||
ip=str(self.ip),
|
||||
make=self.make,
|
||||
model=self.model,
|
||||
expected_chips=self.expected_chips * self.expected_hashboards,
|
||||
expected_hashboards=self.expected_hashboards,
|
||||
hashboards=[
|
||||
|
||||
@@ -13,346 +13,10 @@
|
||||
# See the License for the specific language governing permissions and -
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
import logging
|
||||
from typing import List, Optional
|
||||
|
||||
from pyasic.config import MinerConfig
|
||||
from pyasic.data import Fan, HashBoard
|
||||
from pyasic.data.error_codes import InnosiliconError, MinerErrorData
|
||||
from pyasic.errors import APIError
|
||||
from pyasic.miners.backends import CGMiner
|
||||
from pyasic.miners.backends.innosilicon import Innosilicon
|
||||
from pyasic.miners.types import A10X
|
||||
from pyasic.web.inno import InnosiliconWebAPI
|
||||
|
||||
|
||||
class CGMinerA10X(CGMiner, A10X):
|
||||
def __init__(self, ip: str, api_ver: str = "0.0.0") -> None:
|
||||
super().__init__(ip, api_ver=api_ver)
|
||||
self.ip = ip
|
||||
self.web = InnosiliconWebAPI(ip)
|
||||
|
||||
async def fault_light_on(self) -> bool:
|
||||
return False
|
||||
|
||||
async def fault_light_off(self) -> bool:
|
||||
return False
|
||||
|
||||
async def get_config(self, web_pools: dict = None) -> MinerConfig:
|
||||
if not web_pools:
|
||||
try:
|
||||
web_pools = await self.web.pools()
|
||||
except APIError as e:
|
||||
logging.warning(e)
|
||||
|
||||
if web_pools:
|
||||
if "pools" in web_pools.keys():
|
||||
cfg = MinerConfig().from_raw(web_pools)
|
||||
self.config = cfg
|
||||
return self.config
|
||||
|
||||
async def reboot(self) -> bool:
|
||||
try:
|
||||
data = await self.web.reboot()
|
||||
except APIError:
|
||||
pass
|
||||
else:
|
||||
return data["success"]
|
||||
|
||||
async def restart_cgminer(self) -> bool:
|
||||
try:
|
||||
data = await self.web.restart_cgminer()
|
||||
except APIError:
|
||||
pass
|
||||
else:
|
||||
return data["success"]
|
||||
|
||||
async def restart_backend(self) -> bool:
|
||||
return await self.restart_cgminer()
|
||||
|
||||
async def stop_mining(self) -> bool:
|
||||
return False
|
||||
# data = await self.web.poweroff()
|
||||
# try:
|
||||
# return data["success"]
|
||||
# except KeyError:
|
||||
# return False
|
||||
|
||||
async def resume_mining(self) -> bool:
|
||||
return False
|
||||
# data = await self.web.restart_cgminer()
|
||||
# print(data)
|
||||
# try:
|
||||
# return data["success"]
|
||||
# except KeyError:
|
||||
# return False
|
||||
|
||||
async def send_config(self, config: MinerConfig, user_suffix: str = None) -> None:
|
||||
pass
|
||||
# doesnt work for some reason
|
||||
# self.config = config
|
||||
# await self.web.update_pools(config.as_inno(user_suffix=user_suffix))
|
||||
|
||||
##################################################
|
||||
### DATA GATHERING FUNCTIONS (get_{some_data}) ###
|
||||
##################################################
|
||||
|
||||
async def get_mac(
|
||||
self, web_get_all: dict = None, web_overview: dict = None
|
||||
) -> Optional[str]:
|
||||
if web_get_all:
|
||||
web_get_all = web_get_all["all"]
|
||||
|
||||
if not web_get_all and not web_overview:
|
||||
try:
|
||||
web_overview = await self.web.overview()
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
if web_get_all:
|
||||
try:
|
||||
mac = web_get_all["mac"]
|
||||
return mac.upper()
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
if web_overview:
|
||||
try:
|
||||
mac = web_overview["version"]["ethaddr"]
|
||||
return mac.upper()
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
async def get_hashrate(
|
||||
self, api_summary: dict = None, web_get_all: dict = None
|
||||
) -> Optional[float]:
|
||||
if web_get_all:
|
||||
web_get_all = web_get_all["all"]
|
||||
|
||||
if not api_summary and not web_get_all:
|
||||
try:
|
||||
api_summary = await self.api.summary()
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
if web_get_all:
|
||||
try:
|
||||
return round(float(web_get_all["total_hash"]["Hash Rate"] / 1000000), 5)
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
if api_summary:
|
||||
try:
|
||||
return round(
|
||||
float(api_summary["SUMMARY"][0]["MHS 1m"] / 1000000000000), 5
|
||||
)
|
||||
except (KeyError, IndexError):
|
||||
pass
|
||||
|
||||
async def get_hashboards(
|
||||
self, api_stats: dict = None, web_get_all: dict = None
|
||||
) -> List[HashBoard]:
|
||||
hashboards = [
|
||||
HashBoard(slot=i, expected_chips=self.expected_chips)
|
||||
for i in range(self.expected_hashboards)
|
||||
]
|
||||
if web_get_all:
|
||||
web_get_all = web_get_all["all"]
|
||||
|
||||
if not api_stats:
|
||||
try:
|
||||
api_stats = await self.api.stats()
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
if not web_get_all:
|
||||
try:
|
||||
web_get_all = await self.web.get_all()
|
||||
except APIError:
|
||||
pass
|
||||
else:
|
||||
web_get_all = web_get_all["all"]
|
||||
|
||||
if api_stats:
|
||||
if api_stats.get("STATS"):
|
||||
for board in api_stats["STATS"]:
|
||||
try:
|
||||
idx = board["Chain ID"]
|
||||
chips = board["Num active chips"]
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
hashboards[idx].chips = chips
|
||||
hashboards[idx].missing = False
|
||||
|
||||
if web_get_all:
|
||||
if web_get_all.get("chain"):
|
||||
for board in web_get_all["chain"]:
|
||||
idx = board.get("ASC")
|
||||
if idx is not None:
|
||||
temp = board.get("Temp min")
|
||||
if temp:
|
||||
hashboards[idx].temp = round(temp)
|
||||
|
||||
hashrate = board.get("Hash Rate H")
|
||||
if hashrate:
|
||||
hashboards[idx].hashrate = round(
|
||||
hashrate / 1000000000000, 5
|
||||
)
|
||||
|
||||
chip_temp = board.get("Temp max")
|
||||
if chip_temp:
|
||||
hashboards[idx].chip_temp = round(chip_temp)
|
||||
|
||||
return hashboards
|
||||
|
||||
async def get_wattage(
|
||||
self, web_get_all: dict = None, api_stats: dict = None
|
||||
) -> Optional[int]:
|
||||
if web_get_all:
|
||||
web_get_all = web_get_all["all"]
|
||||
|
||||
if not web_get_all:
|
||||
try:
|
||||
web_get_all = await self.web.get_all()
|
||||
except APIError:
|
||||
pass
|
||||
else:
|
||||
web_get_all = web_get_all["all"]
|
||||
|
||||
if web_get_all:
|
||||
try:
|
||||
return web_get_all["power"]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
if not api_stats:
|
||||
try:
|
||||
api_stats = await self.api.stats()
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
if api_stats:
|
||||
if api_stats.get("STATS"):
|
||||
for board in api_stats["STATS"]:
|
||||
try:
|
||||
wattage = board["power"]
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
wattage = int(wattage)
|
||||
return wattage
|
||||
|
||||
async def get_fans(self, web_get_all: dict = None) -> List[Fan]:
|
||||
if web_get_all:
|
||||
web_get_all = web_get_all["all"]
|
||||
|
||||
if not web_get_all:
|
||||
try:
|
||||
web_get_all = await self.web.get_all()
|
||||
except APIError:
|
||||
pass
|
||||
else:
|
||||
web_get_all = web_get_all["all"]
|
||||
|
||||
fans = [Fan() for _ in range(self.fan_count)]
|
||||
if web_get_all:
|
||||
try:
|
||||
spd = web_get_all["fansSpeed"]
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
round((int(spd) * 6000) / 100)
|
||||
for i in range(self.fan_count):
|
||||
fans[i].speed = spd
|
||||
|
||||
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, web_get_error_detail: dict = None
|
||||
) -> List[MinerErrorData]: # noqa: named this way for automatic functionality
|
||||
errors = []
|
||||
if not web_get_error_detail:
|
||||
try:
|
||||
web_get_error_detail = await self.web.get_error_detail()
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
if web_get_error_detail:
|
||||
try:
|
||||
# only 1 error?
|
||||
# TODO: check if this should be a loop, can't remember.
|
||||
err = web_get_error_detail["code"]
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
err = int(err)
|
||||
if not err == 0:
|
||||
errors.append(InnosiliconError(error_code=err))
|
||||
return errors
|
||||
|
||||
async def get_fw_ver(self, api_version: dict = None) -> Optional[str]:
|
||||
if self.fw_ver:
|
||||
return self.fw_ver
|
||||
|
||||
if not api_version:
|
||||
try:
|
||||
api_version = await self.api.version()
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
if api_version:
|
||||
try:
|
||||
self.fw_ver = api_version["VERSION"][0]["CGMiner"].split("-")[-1:][0]
|
||||
except (KeyError, IndexError):
|
||||
pass
|
||||
|
||||
return self.fw_ver
|
||||
|
||||
async def get_wattage_limit(self, web_get_all: dict = None) -> Optional[int]:
|
||||
if web_get_all:
|
||||
web_get_all = web_get_all["all"]
|
||||
|
||||
if not web_get_all:
|
||||
try:
|
||||
web_get_all = await self.web.get_all()
|
||||
except APIError:
|
||||
pass
|
||||
else:
|
||||
web_get_all = web_get_all["all"]
|
||||
|
||||
if web_get_all:
|
||||
try:
|
||||
level = web_get_all["running_mode"]["level"]
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
# this is very possibly not correct.
|
||||
level = int(level)
|
||||
limit = 1250 + (250 * level)
|
||||
return limit
|
||||
class InnosiliconA10X(Innosilicon, A10X):
|
||||
pass
|
||||
|
||||
@@ -14,4 +14,4 @@
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
from .A10X import CGMinerA10X
|
||||
from .A10X import InnosiliconA10X
|
||||
|
||||
@@ -13,307 +13,10 @@
|
||||
# See the License for the specific language governing permissions and -
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
import logging
|
||||
from typing import List, Optional
|
||||
|
||||
from pyasic.config import MinerConfig
|
||||
from pyasic.data import Fan, HashBoard
|
||||
from pyasic.data.error_codes import InnosiliconError, MinerErrorData
|
||||
from pyasic.errors import APIError
|
||||
from pyasic.miners.backends import CGMiner
|
||||
from pyasic.miners.backends.innosilicon import Innosilicon
|
||||
from pyasic.miners.types import T3HPlus
|
||||
from pyasic.web.inno import InnosiliconWebAPI
|
||||
|
||||
|
||||
class CGMinerT3HPlus(CGMiner, T3HPlus):
|
||||
def __init__(self, ip: str, api_ver: str = "0.0.0") -> None:
|
||||
super().__init__(ip, api_ver=api_ver)
|
||||
self.ip = ip
|
||||
self.web = InnosiliconWebAPI(ip)
|
||||
|
||||
async def fault_light_on(self) -> bool:
|
||||
return False
|
||||
|
||||
async def fault_light_off(self) -> bool:
|
||||
return False
|
||||
|
||||
async def get_config(self, api_pools: dict = None) -> MinerConfig:
|
||||
# get pool data
|
||||
try:
|
||||
pools = await self.api.pools()
|
||||
except APIError:
|
||||
return self.config
|
||||
|
||||
self.config = MinerConfig.from_api(pools)
|
||||
return self.config
|
||||
|
||||
async def reboot(self) -> bool:
|
||||
try:
|
||||
data = await self.web.reboot()
|
||||
except APIError:
|
||||
pass
|
||||
else:
|
||||
return data["success"]
|
||||
|
||||
async def restart_cgminer(self) -> bool:
|
||||
try:
|
||||
data = await self.web.restart_cgminer()
|
||||
except APIError:
|
||||
pass
|
||||
else:
|
||||
return data["success"]
|
||||
|
||||
async def restart_backend(self) -> bool:
|
||||
return await self.restart_cgminer()
|
||||
|
||||
async def send_config(self, config: MinerConfig, user_suffix: str = None) -> None:
|
||||
self.config = config
|
||||
await self.web.update_pools(config.as_inno(user_suffix=user_suffix))
|
||||
|
||||
##################################################
|
||||
### DATA GATHERING FUNCTIONS (get_{some_data}) ###
|
||||
##################################################
|
||||
|
||||
async def get_mac(
|
||||
self, web_get_all: dict = None, web_overview: dict = None
|
||||
) -> Optional[str]:
|
||||
if web_get_all:
|
||||
web_get_all = web_get_all["all"]
|
||||
|
||||
if not web_get_all and not web_overview:
|
||||
try:
|
||||
web_overview = await self.web.overview()
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
if web_get_all:
|
||||
try:
|
||||
mac = web_get_all["mac"]
|
||||
return mac.upper()
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
if web_overview:
|
||||
try:
|
||||
mac = web_overview["version"]["ethaddr"]
|
||||
return mac.upper()
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
async def get_hashrate(
|
||||
self, api_summary: dict = None, web_get_all: dict = None
|
||||
) -> Optional[float]:
|
||||
if web_get_all:
|
||||
web_get_all = web_get_all["all"]
|
||||
|
||||
if not api_summary and not web_get_all:
|
||||
try:
|
||||
api_summary = await self.api.summary()
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
if web_get_all:
|
||||
try:
|
||||
return round(
|
||||
float(web_get_all["total_hash"]["Hash Rate H"] / 1000000000000), 2
|
||||
)
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
if api_summary:
|
||||
try:
|
||||
return round(float(api_summary["SUMMARY"][0]["MHS 1m"] / 1000000), 2)
|
||||
except (KeyError, IndexError):
|
||||
pass
|
||||
|
||||
async def get_hashboards(
|
||||
self, api_stats: dict = None, web_get_all: dict = None
|
||||
) -> List[HashBoard]:
|
||||
if web_get_all:
|
||||
web_get_all = web_get_all["all"]
|
||||
|
||||
hashboards = [
|
||||
HashBoard(slot=i, expected_chips=self.expected_chips)
|
||||
for i in range(self.expected_hashboards)
|
||||
]
|
||||
|
||||
if not api_stats:
|
||||
try:
|
||||
api_stats = await self.api.stats()
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
if not web_get_all:
|
||||
try:
|
||||
web_get_all = await self.web.get_all()
|
||||
except APIError:
|
||||
pass
|
||||
else:
|
||||
web_get_all = web_get_all["all"]
|
||||
|
||||
if api_stats:
|
||||
if api_stats.get("STATS"):
|
||||
for board in api_stats["STATS"]:
|
||||
try:
|
||||
idx = board["Chain ID"]
|
||||
chips = board["Num active chips"]
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
hashboards[idx].chips = chips
|
||||
hashboards[idx].missing = False
|
||||
|
||||
if web_get_all:
|
||||
if web_get_all.get("chain"):
|
||||
for board in web_get_all["chain"]:
|
||||
idx = board.get("ASC")
|
||||
if idx is not None:
|
||||
temp = board.get("Temp min")
|
||||
if temp:
|
||||
hashboards[idx].temp = round(temp)
|
||||
|
||||
hashrate = board.get("Hash Rate H")
|
||||
if hashrate:
|
||||
hashboards[idx].hashrate = round(
|
||||
hashrate / 1000000000000, 2
|
||||
)
|
||||
|
||||
chip_temp = board.get("Temp max")
|
||||
if chip_temp:
|
||||
hashboards[idx].chip_temp = round(chip_temp)
|
||||
|
||||
return hashboards
|
||||
|
||||
async def get_wattage(
|
||||
self, web_get_all: dict = None, api_stats: dict = None
|
||||
) -> Optional[int]:
|
||||
if web_get_all:
|
||||
web_get_all = web_get_all["all"]
|
||||
|
||||
if not web_get_all:
|
||||
try:
|
||||
web_get_all = await self.web.get_all()
|
||||
except APIError:
|
||||
pass
|
||||
else:
|
||||
web_get_all = web_get_all["all"]
|
||||
|
||||
if web_get_all:
|
||||
try:
|
||||
return web_get_all["power"]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
if not api_stats:
|
||||
try:
|
||||
api_stats = await self.api.stats()
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
if api_stats:
|
||||
if api_stats.get("STATS"):
|
||||
for board in api_stats["STATS"]:
|
||||
try:
|
||||
wattage = board["power"]
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
wattage = int(wattage)
|
||||
return wattage
|
||||
|
||||
async def get_fans(self, web_get_all: dict = None) -> List[Fan]:
|
||||
if web_get_all:
|
||||
web_get_all = web_get_all["all"]
|
||||
|
||||
if not web_get_all:
|
||||
try:
|
||||
web_get_all = await self.web.get_all()
|
||||
except APIError:
|
||||
pass
|
||||
else:
|
||||
web_get_all = web_get_all["all"]
|
||||
|
||||
fans = [Fan() for _ in range(self.fan_count)]
|
||||
if web_get_all:
|
||||
try:
|
||||
spd = web_get_all["fansSpeed"]
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
round((int(spd) * 6000) / 100)
|
||||
for i in range(self.fan_count):
|
||||
fans[i].speed = spd
|
||||
|
||||
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, web_get_error_detail: dict = None
|
||||
) -> List[MinerErrorData]: # noqa: named this way for automatic functionality
|
||||
errors = []
|
||||
if not web_get_error_detail:
|
||||
try:
|
||||
web_get_error_detail = await self.web.get_error_detail()
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
if web_get_error_detail:
|
||||
try:
|
||||
# only 1 error?
|
||||
# TODO: check if this should be a loop, can't remember.
|
||||
err = web_get_error_detail["code"]
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
err = int(err)
|
||||
if not err == 0:
|
||||
errors.append(InnosiliconError(error_code=err))
|
||||
return errors
|
||||
|
||||
async def get_wattage_limit(self, web_get_all: dict = None) -> Optional[int]:
|
||||
if web_get_all:
|
||||
web_get_all = web_get_all["all"]
|
||||
|
||||
if not web_get_all:
|
||||
try:
|
||||
web_get_all = await self.web.get_all()
|
||||
except APIError:
|
||||
pass
|
||||
else:
|
||||
web_get_all = web_get_all["all"]
|
||||
|
||||
if web_get_all:
|
||||
try:
|
||||
level = web_get_all["running_mode"]["level"]
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
# this is very possibly not correct.
|
||||
level = int(level)
|
||||
limit = 1250 + (250 * level)
|
||||
return limit
|
||||
class InnosiliconT3HPlus(Innosilicon, T3HPlus):
|
||||
pass
|
||||
|
||||
@@ -14,4 +14,4 @@
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
from .T3H import CGMinerT3HPlus
|
||||
from .T3H import InnosiliconT3HPlus
|
||||
|
||||
@@ -326,8 +326,8 @@ MINER_CLASSES = {
|
||||
},
|
||||
MinerTypes.INNOSILICON: {
|
||||
None: CGMiner,
|
||||
"T3H+": CGMinerT3HPlus,
|
||||
"A10X": CGMinerA10X,
|
||||
"T3H+": InnosiliconT3HPlus,
|
||||
"A10X": InnosiliconA10X,
|
||||
},
|
||||
MinerTypes.GOLDSHELL: {
|
||||
None: BFGMiner,
|
||||
@@ -476,6 +476,7 @@ class MinerFactory:
|
||||
fn = miner_model_fns.get(miner_type)
|
||||
|
||||
if fn is not None:
|
||||
# noinspection PyArgumentList
|
||||
task = asyncio.create_task(fn(ip))
|
||||
try:
|
||||
miner_model = await asyncio.wait_for(
|
||||
@@ -484,15 +485,10 @@ class MinerFactory:
|
||||
except asyncio.TimeoutError:
|
||||
pass
|
||||
|
||||
boser_enabled = None
|
||||
if miner_type == MinerTypes.BRAIINS_OS:
|
||||
boser_enabled = await self.get_boser_braiins_os(ip)
|
||||
|
||||
miner = self._select_miner_from_classes(
|
||||
ip,
|
||||
miner_type=miner_type,
|
||||
miner_model=miner_model,
|
||||
boser_enabled=boser_enabled,
|
||||
)
|
||||
|
||||
if miner is not None and not isinstance(miner, UnknownMiner):
|
||||
@@ -775,13 +771,9 @@ class MinerFactory:
|
||||
ip: ipaddress.ip_address,
|
||||
miner_model: Union[str, None],
|
||||
miner_type: Union[MinerTypes, None],
|
||||
boser_enabled: bool = None,
|
||||
) -> AnyMiner:
|
||||
kwargs = {}
|
||||
if boser_enabled is not None:
|
||||
kwargs["boser"] = boser_enabled
|
||||
try:
|
||||
return MINER_CLASSES[miner_type][str(miner_model).upper()](ip, **kwargs)
|
||||
return MINER_CLASSES[miner_type][str(miner_model).upper()](ip)
|
||||
except LookupError:
|
||||
if miner_type in MINER_CLASSES:
|
||||
return MINER_CLASSES[miner_type][None](ip)
|
||||
@@ -909,15 +901,6 @@ class MinerFactory:
|
||||
except (httpx.HTTPError, LookupError):
|
||||
pass
|
||||
|
||||
async def get_boser_braiins_os(self, ip: str):
|
||||
# TODO: refine this check
|
||||
try:
|
||||
sock_json_data = await self.send_api_command(ip, "version")
|
||||
return sock_json_data["STATUS"][0]["Msg"].split(" ")[0].upper() == "BOSER"
|
||||
except LookupError:
|
||||
# let the bosminer class decide
|
||||
return None
|
||||
|
||||
async def get_miner_model_vnish(self, ip: str) -> Optional[str]:
|
||||
sock_json_data = await self.send_api_command(ip, "stats")
|
||||
try:
|
||||
|
||||
@@ -21,6 +21,6 @@ class Z15(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 = "Z15"
|
||||
self.raw_model = "Z15"
|
||||
self.expected_chips = 3
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -21,7 +21,7 @@ class S17(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 = "S17"
|
||||
self.raw_model = "S17"
|
||||
self.expected_chips = 48
|
||||
self.fan_count = 4
|
||||
|
||||
@@ -29,7 +29,7 @@ class S17(AntMiner): # noqa - ignore ABC method implementation
|
||||
class S17Plus(AntMiner): # noqa - ignore ABC method implementation
|
||||
def __init__(self, ip: str, api_ver: str = "0.0.0"):
|
||||
super().__init__(ip, api_ver)
|
||||
self.model = "S17+"
|
||||
self.raw_model = "S17+"
|
||||
self.expected_chips = 65
|
||||
self.fan_count = 4
|
||||
|
||||
@@ -38,7 +38,7 @@ class S17Pro(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 = "S17 Pro"
|
||||
self.raw_model = "S17 Pro"
|
||||
self.expected_chips = 48
|
||||
self.fan_count = 4
|
||||
|
||||
@@ -47,6 +47,6 @@ class S17e(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 = "S17e"
|
||||
self.raw_model = "S17e"
|
||||
self.expected_chips = 135
|
||||
self.fan_count = 4
|
||||
|
||||
@@ -21,7 +21,7 @@ class T17(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 = "T17"
|
||||
self.raw_model = "T17"
|
||||
self.expected_chips = 30
|
||||
self.fan_count = 4
|
||||
|
||||
@@ -30,7 +30,7 @@ class T17Plus(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 = "T17+"
|
||||
self.raw_model = "T17+"
|
||||
self.expected_chips = 44
|
||||
self.fan_count = 4
|
||||
|
||||
@@ -39,6 +39,6 @@ class T17e(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 = "T17e"
|
||||
self.raw_model = "T17e"
|
||||
self.expected_chips = 78
|
||||
self.fan_count = 4
|
||||
|
||||
@@ -21,7 +21,7 @@ class S19(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"
|
||||
self.raw_model = "S19"
|
||||
self.expected_chips = 76
|
||||
self.fan_count = 4
|
||||
|
||||
@@ -30,7 +30,7 @@ class S19NoPIC(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 No PIC"
|
||||
self.raw_model = "S19 No PIC"
|
||||
self.expected_chips = 88
|
||||
self.fan_count = 4
|
||||
|
||||
@@ -39,7 +39,7 @@ class S19Pro(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"
|
||||
self.raw_model = "S19 Pro"
|
||||
self.expected_chips = 114
|
||||
self.fan_count = 4
|
||||
|
||||
@@ -48,7 +48,7 @@ class S19i(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 = "S19i"
|
||||
self.raw_model = "S19i"
|
||||
self.expected_chips = 80
|
||||
self.fan_count = 4
|
||||
|
||||
@@ -57,7 +57,7 @@ class S19Plus(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+"
|
||||
self.raw_model = "S19+"
|
||||
self.expected_chips = 80
|
||||
self.fan_count = 4
|
||||
|
||||
@@ -66,7 +66,7 @@ class S19ProPlus(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+"
|
||||
self.raw_model = "S19 Pro+"
|
||||
self.expected_chips = 120
|
||||
self.fan_count = 4
|
||||
|
||||
@@ -75,7 +75,7 @@ class S19XP(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 XP"
|
||||
self.raw_model = "S19 XP"
|
||||
self.expected_chips = 110
|
||||
self.fan_count = 4
|
||||
|
||||
@@ -84,7 +84,7 @@ class S19a(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 = "S19a"
|
||||
self.raw_model = "S19a"
|
||||
self.expected_chips = 72
|
||||
self.fan_count = 4
|
||||
|
||||
@@ -93,7 +93,7 @@ class S19aPro(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 = "S19a Pro"
|
||||
self.raw_model = "S19a Pro"
|
||||
self.expected_chips = 100
|
||||
self.fan_count = 4
|
||||
|
||||
@@ -102,7 +102,7 @@ class S19j(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 = "S19j"
|
||||
self.raw_model = "S19j"
|
||||
self.expected_chips = 114
|
||||
self.fan_count = 4
|
||||
|
||||
@@ -111,7 +111,7 @@ class S19jNoPIC(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 = "S19j No PIC"
|
||||
self.raw_model = "S19j No PIC"
|
||||
self.expected_chips = 88
|
||||
self.fan_count = 4
|
||||
|
||||
@@ -120,7 +120,7 @@ class S19jPro(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 = "S19j Pro"
|
||||
self.raw_model = "S19j Pro"
|
||||
self.expected_chips = 126
|
||||
self.fan_count = 4
|
||||
|
||||
@@ -129,7 +129,7 @@ class S19jProPlus(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 = "S19j Pro+"
|
||||
self.raw_model = "S19j Pro+"
|
||||
self.expected_chips = 120
|
||||
self.fan_count = 4
|
||||
|
||||
@@ -138,7 +138,7 @@ class S19kPro(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 = "S19k Pro"
|
||||
self.raw_model = "S19k Pro"
|
||||
self.expected_chips = 77
|
||||
self.fan_count = 4
|
||||
|
||||
@@ -147,7 +147,7 @@ class S19L(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 = "S19L"
|
||||
self.raw_model = "S19L"
|
||||
self.expected_chips = 76
|
||||
self.fan_count = 4
|
||||
|
||||
@@ -156,7 +156,7 @@ class S19kProNoPIC(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 = "S19k Pro No PIC"
|
||||
self.raw_model = "S19k Pro No PIC"
|
||||
self.expected_chips = 77
|
||||
self.fan_count = 4
|
||||
|
||||
@@ -165,7 +165,7 @@ 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.raw_model = "S19 Pro Hydro"
|
||||
self.expected_chips = 180
|
||||
self.expected_hashboards = 4
|
||||
self.fan_count = 0
|
||||
|
||||
@@ -21,6 +21,6 @@ class T19(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 = "T19"
|
||||
self.raw_model = "T19"
|
||||
self.expected_chips = 76
|
||||
self.fan_count = 4
|
||||
|
||||
@@ -21,7 +21,7 @@ class D3(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 = "D3"
|
||||
self.raw_model = "D3"
|
||||
self.expected_chips = 60
|
||||
self.expected_hashboards = 3
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -21,7 +21,7 @@ class HS3(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 = "HS3"
|
||||
self.raw_model = "HS3"
|
||||
self.expected_chips = 92
|
||||
self.expected_hashboards = 3
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -20,6 +20,6 @@ class L3Plus(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 = "L3+"
|
||||
self.raw_model = "L3+"
|
||||
self.expected_chips = 72
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -21,7 +21,7 @@ class DR5(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 = "DR5"
|
||||
self.raw_model = "DR5"
|
||||
self.expected_chips = 72
|
||||
self.expected_hashboards = 3
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -20,6 +20,6 @@ class L7(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 = "L7"
|
||||
self.raw_model = "L7"
|
||||
self.expected_chips = 120
|
||||
self.fan_count = 4
|
||||
|
||||
@@ -21,7 +21,7 @@ class E9Pro(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 = "E9Pro"
|
||||
self.raw_model = "E9Pro"
|
||||
self.expected_chips = 8
|
||||
self.expected_hashboards = 2
|
||||
self.fan_count = 4
|
||||
|
||||
@@ -21,7 +21,7 @@ class S9(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 = "S9"
|
||||
self.raw_model = "S9"
|
||||
self.expected_chips = 63
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -30,7 +30,7 @@ class S9i(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 = "S9i"
|
||||
self.raw_model = "S9i"
|
||||
self.expected_chips = 63
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -39,6 +39,6 @@ class S9j(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 = "S9j"
|
||||
self.raw_model = "S9j"
|
||||
self.expected_chips = 63
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -21,6 +21,6 @@ class T9(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 = "T9"
|
||||
self.raw_model = "T9"
|
||||
self.expected_chips = 54
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -21,6 +21,6 @@ class Avalon1026(AvalonMiner): # 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 = "Avalon 1026"
|
||||
self.raw_model = "Avalon 1026"
|
||||
self.expected_chips = 80
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -21,6 +21,6 @@ class Avalon1047(AvalonMiner): # 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 = "Avalon 1047"
|
||||
self.raw_model = "Avalon 1047"
|
||||
self.expected_chips = 80
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -21,6 +21,6 @@ class Avalon1066(AvalonMiner): # 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 = "Avalon 1066"
|
||||
self.raw_model = "Avalon 1066"
|
||||
self.expected_chips = 114
|
||||
self.fan_count = 4
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
# See the License for the specific language governing permissions and -
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
import warnings
|
||||
|
||||
from pyasic.miners.makes import AvalonMiner
|
||||
|
||||
@@ -22,6 +21,6 @@ class Avalon1166Pro(AvalonMiner): # 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 = "Avalon 1166 Pro"
|
||||
self.raw_model = "Avalon 1166 Pro"
|
||||
self.expected_chips = 120
|
||||
self.fan_count = 4
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
# See the License for the specific language governing permissions and -
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
import warnings
|
||||
|
||||
from pyasic.miners.makes import AvalonMiner
|
||||
|
||||
@@ -22,6 +21,6 @@ class Avalon1246(AvalonMiner): # 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 = "Avalon 1246"
|
||||
self.raw_model = "Avalon 1246"
|
||||
self.expected_chips = 120
|
||||
self.fan_count = 4
|
||||
|
||||
@@ -21,7 +21,7 @@ class Avalon721(AvalonMiner): # 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 = "Avalon 721"
|
||||
self.raw_model = "Avalon 721"
|
||||
self.expected_hashboards = 4
|
||||
self.expected_chips = 18
|
||||
self.fan_count = 1
|
||||
|
||||
@@ -21,7 +21,7 @@ class Avalon741(AvalonMiner): # 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 = "Avalon 741"
|
||||
self.raw_model = "Avalon 741"
|
||||
self.expected_hashboards = 4
|
||||
self.expected_chips = 22
|
||||
self.fan_count = 1
|
||||
|
||||
@@ -21,7 +21,7 @@ class Avalon761(AvalonMiner): # 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 = "Avalon 761"
|
||||
self.raw_model = "Avalon 761"
|
||||
self.expected_hashboards = 4
|
||||
self.expected_chips = 18
|
||||
self.fan_count = 1
|
||||
|
||||
@@ -21,7 +21,7 @@ class Avalon821(AvalonMiner): # 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 = "Avalon 821"
|
||||
self.raw_model = "Avalon 821"
|
||||
self.expected_hashboards = 4
|
||||
self.expected_chips = 26
|
||||
self.fan_count = 1
|
||||
|
||||
@@ -21,7 +21,7 @@ class Avalon841(AvalonMiner): # 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 = "Avalon 841"
|
||||
self.raw_model = "Avalon 841"
|
||||
self.expected_hashboards = 4
|
||||
self.expected_chips = 26
|
||||
self.fan_count = 1
|
||||
|
||||
@@ -21,7 +21,7 @@ class Avalon851(AvalonMiner): # 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 = "Avalon 851"
|
||||
self.raw_model = "Avalon 851"
|
||||
self.expected_hashboards = 4
|
||||
self.expected_chips = 26
|
||||
self.fan_count = 1
|
||||
|
||||
@@ -21,7 +21,7 @@ class Avalon921(AvalonMiner): # 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 = "Avalon 921"
|
||||
self.raw_model = "Avalon 921"
|
||||
self.expected_hashboards = 4
|
||||
self.expected_chips = 26
|
||||
self.fan_count = 1
|
||||
|
||||
@@ -20,7 +20,7 @@ class CK5(GoldshellMiner): # 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 = "CK5"
|
||||
self.raw_model = "CK5"
|
||||
self.expected_hashboards = 4
|
||||
self.expected_chips = 46
|
||||
self.fan_count = 4
|
||||
|
||||
@@ -20,7 +20,7 @@ class HS5(GoldshellMiner): # 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 = "HS5"
|
||||
self.raw_model = "HS5"
|
||||
self.expected_hashboards = 4
|
||||
self.expected_chips = 46
|
||||
self.fan_count = 4
|
||||
|
||||
@@ -20,7 +20,7 @@ class KD5(GoldshellMiner): # 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 = "KD5"
|
||||
self.raw_model = "KD5"
|
||||
self.expected_hashboards = 4
|
||||
self.expected_chips = 46
|
||||
self.fan_count = 4
|
||||
|
||||
@@ -20,7 +20,7 @@ class KDMax(GoldshellMiner): # 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 = "KD Max"
|
||||
self.raw_model = "KD Max"
|
||||
self.expected_hashboards = 3
|
||||
self.expected_chips = 84
|
||||
self.fan_count = 4
|
||||
|
||||
@@ -20,4 +20,4 @@ class A10X(InnosiliconMiner): # noqa - ignore ABC method implementation
|
||||
def __init__(self, ip: str, api_ver: str = "0.0.0") -> None:
|
||||
super().__init__(ip, api_ver)
|
||||
self.ip = ip
|
||||
self.model = "A10X"
|
||||
self.raw_model = "A10X"
|
||||
|
||||
@@ -21,6 +21,6 @@ class T3HPlus(InnosiliconMiner): # noqa - ignore ABC method implementation
|
||||
def __init__(self, ip: str, api_ver: str = "0.0.0") -> None:
|
||||
super().__init__(ip, api_ver)
|
||||
self.ip = ip
|
||||
self.model = "T3H+"
|
||||
self.raw_model = "T3H+"
|
||||
self.expected_chips = 114
|
||||
self.fan_count = 4
|
||||
|
||||
@@ -21,6 +21,6 @@ class M20V10(WhatsMiner): # 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 = "M20 V10"
|
||||
self.raw_model = "M20 V10"
|
||||
self.expected_chips = 70
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -21,7 +21,7 @@ class M20PV10(WhatsMiner): # 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 = "M20P V10"
|
||||
self.raw_model = "M20P V10"
|
||||
self.expected_chips = 156
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -30,6 +30,6 @@ class M20PV30(WhatsMiner): # 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 = "M20P V30"
|
||||
self.raw_model = "M20P V30"
|
||||
self.expected_chips = 148
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
import warnings
|
||||
|
||||
from pyasic.miners.makes import WhatsMiner
|
||||
|
||||
|
||||
@@ -23,7 +21,7 @@ class M20SV10(WhatsMiner): # 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 = "M20S V10"
|
||||
self.raw_model = "M20S V10"
|
||||
self.expected_chips = 105
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -32,7 +30,7 @@ class M20SV20(WhatsMiner): # 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 = "M20S V20"
|
||||
self.raw_model = "M20S V20"
|
||||
self.expected_chips = 111
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -41,6 +39,6 @@ class M20SV30(WhatsMiner): # 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 = "M20S V30"
|
||||
self.raw_model = "M20S V30"
|
||||
self.expected_chips = 140
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -23,7 +23,7 @@ class M20SPlusV30(WhatsMiner): # 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 = "M20S+ V30"
|
||||
self.raw_model = "M20S+ V30"
|
||||
self.expected_chips = 0
|
||||
warnings.warn(
|
||||
"Unknown chip count for miner type M20S+ V30, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
import warnings
|
||||
|
||||
from pyasic.miners.makes import WhatsMiner
|
||||
|
||||
|
||||
@@ -23,6 +21,6 @@ class M21V10(WhatsMiner): # 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 = "M21 V10"
|
||||
self.raw_model = "M21 V10"
|
||||
self.expected_chips = 33
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
import warnings
|
||||
|
||||
from pyasic.miners.makes import WhatsMiner
|
||||
|
||||
|
||||
@@ -23,7 +21,7 @@ class M21SV20(WhatsMiner): # 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 = "M21S V20"
|
||||
self.raw_model = "M21S V20"
|
||||
self.expected_chips = 66
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -32,7 +30,7 @@ class M21SV60(WhatsMiner): # 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 = "M21S V60"
|
||||
self.raw_model = "M21S V60"
|
||||
self.expected_chips = 105
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -41,6 +39,6 @@ class M21SV70(WhatsMiner): # 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 = "M21S V70"
|
||||
self.raw_model = "M21S V70"
|
||||
self.expected_chips = 111
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -23,7 +23,7 @@ class M21SPlusV20(WhatsMiner): # 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 = "M21S+ V20"
|
||||
self.raw_model = "M21S+ V20"
|
||||
self.expected_chips = 0
|
||||
warnings.warn(
|
||||
"Unknown chip count for miner type M21S+ V20, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
import warnings
|
||||
|
||||
from pyasic.miners.makes import WhatsMiner
|
||||
|
||||
|
||||
@@ -23,6 +21,6 @@ class M29V10(WhatsMiner): # 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 = "M29 V10"
|
||||
self.raw_model = "M29 V10"
|
||||
self.expected_chips = 50
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
import warnings
|
||||
|
||||
from pyasic.miners.makes import WhatsMiner
|
||||
|
||||
|
||||
@@ -23,7 +21,7 @@ class M30V10(WhatsMiner): # 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 = "M30 V10"
|
||||
self.raw_model = "M30 V10"
|
||||
self.expected_chips = 105
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -32,6 +30,6 @@ class M30V20(WhatsMiner): # 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 = "M30 V20"
|
||||
self.raw_model = "M30 V20"
|
||||
self.expected_chips = 111
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
import warnings
|
||||
|
||||
from pyasic.miners.makes import WhatsMiner
|
||||
|
||||
|
||||
@@ -23,7 +21,7 @@ class M30KV10(WhatsMiner): # 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 = "M30K V10"
|
||||
self.raw_model = "M30K V10"
|
||||
self.expected_hashboards = 4
|
||||
self.expected_chips = 240
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
import warnings
|
||||
|
||||
from pyasic.miners.makes import WhatsMiner
|
||||
|
||||
|
||||
@@ -23,7 +21,7 @@ class M30LV10(WhatsMiner): # 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 = "M30L V10"
|
||||
self.raw_model = "M30L V10"
|
||||
self.board_num = 4
|
||||
self.expected_chips = 144
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -23,7 +23,7 @@ class M30SV10(WhatsMiner): # 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 = "M30S V10"
|
||||
self.raw_model = "M30S V10"
|
||||
self.expected_chips = 148
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -32,7 +32,7 @@ class M30SV20(WhatsMiner): # 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 = "M30S V20"
|
||||
self.raw_model = "M30S V20"
|
||||
self.expected_chips = 156
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -41,7 +41,7 @@ class M30SV30(WhatsMiner): # 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 = "M30S V30"
|
||||
self.raw_model = "M30S V30"
|
||||
self.expected_chips = 164
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -50,7 +50,7 @@ class M30SV40(WhatsMiner): # 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 = "M30S V40"
|
||||
self.raw_model = "M30S V40"
|
||||
self.expected_chips = 172
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -59,7 +59,7 @@ class M30SV50(WhatsMiner): # 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 = "M30S V50"
|
||||
self.raw_model = "M30S V50"
|
||||
self.expected_chips = 156
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -68,7 +68,7 @@ class M30SV60(WhatsMiner): # 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 = "M30S V60"
|
||||
self.raw_model = "M30S V60"
|
||||
self.expected_chips = 164
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -77,7 +77,7 @@ class M30SV70(WhatsMiner): # 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 = "M30S V70"
|
||||
self.raw_model = "M30S V70"
|
||||
self.expected_chips = 0
|
||||
warnings.warn(
|
||||
"Unknown chip count for miner type M30SV70, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
||||
@@ -89,7 +89,7 @@ class M30SV80(WhatsMiner): # 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 = "M30S V80"
|
||||
self.raw_model = "M30S V80"
|
||||
self.expected_chips = 129
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -98,7 +98,7 @@ class M30SVE10(WhatsMiner): # 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 = "M30S VE10"
|
||||
self.raw_model = "M30S VE10"
|
||||
self.expected_chips = 105
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -107,7 +107,7 @@ class M30SVE20(WhatsMiner): # 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 = "M30S VE20"
|
||||
self.raw_model = "M30S VE20"
|
||||
self.expected_chips = 111
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -116,7 +116,7 @@ class M30SVE30(WhatsMiner): # 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 = "M30S VE30"
|
||||
self.raw_model = "M30S VE30"
|
||||
self.expected_chips = 117
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -125,7 +125,7 @@ class M30SVE40(WhatsMiner): # 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 = "M30S VE40"
|
||||
self.raw_model = "M30S VE40"
|
||||
self.expected_chips = 123
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -134,7 +134,7 @@ class M30SVE50(WhatsMiner): # 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 = "M30S VE50"
|
||||
self.raw_model = "M30S VE50"
|
||||
self.expected_chips = 129
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -143,7 +143,7 @@ class M30SVE60(WhatsMiner): # 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 = "M30S VE60"
|
||||
self.raw_model = "M30S VE60"
|
||||
self.expected_chips = 0
|
||||
warnings.warn(
|
||||
"Unknown chip count for miner type M30SVE60, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
||||
@@ -155,7 +155,7 @@ class M30SVE70(WhatsMiner): # 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 = "M30S VE70"
|
||||
self.raw_model = "M30S VE70"
|
||||
self.expected_chips = 0
|
||||
warnings.warn(
|
||||
"Unknown chip count for miner type M30SVE70, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
||||
@@ -167,7 +167,7 @@ class M30SVF10(WhatsMiner): # 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 = "M30S VF10"
|
||||
self.raw_model = "M30S VF10"
|
||||
self.expected_chips = 70
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -176,7 +176,7 @@ class M30SVF20(WhatsMiner): # 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 = "M30S VF20"
|
||||
self.raw_model = "M30S VF20"
|
||||
self.expected_chips = 74
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -185,7 +185,7 @@ class M30SVF30(WhatsMiner): # 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 = "M30S VF30"
|
||||
self.raw_model = "M30S VF30"
|
||||
self.expected_chips = 78
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -194,7 +194,7 @@ class M30SVG10(WhatsMiner): # 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 = "M30S VG10"
|
||||
self.raw_model = "M30S VG10"
|
||||
self.expected_chips = 66
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -203,7 +203,7 @@ class M30SVG20(WhatsMiner): # 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 = "M30S VG20"
|
||||
self.raw_model = "M30S VG20"
|
||||
self.expected_chips = 70
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -212,7 +212,7 @@ class M30SVG30(WhatsMiner): # 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 = "M30S VG30"
|
||||
self.raw_model = "M30S VG30"
|
||||
self.expected_chips = 74
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -221,7 +221,7 @@ class M30SVG40(WhatsMiner): # 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 = "M30S VG40"
|
||||
self.raw_model = "M30S VG40"
|
||||
self.expected_chips = 78
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -230,7 +230,7 @@ class M30SVH10(WhatsMiner): # 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 = "M30S VH10"
|
||||
self.raw_model = "M30S VH10"
|
||||
self.expected_chips = 64
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -239,7 +239,7 @@ class M30SVH20(WhatsMiner): # 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 = "M30S VH20"
|
||||
self.raw_model = "M30S VH20"
|
||||
self.expected_chips = 66
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -248,7 +248,7 @@ class M30SVH30(WhatsMiner): # 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 = "M30S VH30"
|
||||
self.raw_model = "M30S VH30"
|
||||
self.expected_chips = 0
|
||||
warnings.warn(
|
||||
"Unknown chip count for miner type M30SVH30, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
||||
@@ -260,7 +260,7 @@ class M30SVH40(WhatsMiner): # 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 = "M30S VH40"
|
||||
self.raw_model = "M30S VH40"
|
||||
self.expected_chips = 64
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -269,7 +269,7 @@ class M30SVH50(WhatsMiner): # 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 = "M30S VH50"
|
||||
self.raw_model = "M30S VH50"
|
||||
self.expected_chips = 66
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -278,7 +278,7 @@ class M30SVH60(WhatsMiner): # 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 = "M30S VH60"
|
||||
self.raw_model = "M30S VH60"
|
||||
self.expected_chips = 0
|
||||
warnings.warn(
|
||||
"Unknown chip count for miner type M30SVH60, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
||||
@@ -290,6 +290,6 @@ class M30SVI20(WhatsMiner): # 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 = "M30S VI20"
|
||||
self.raw_model = "M30S VI20"
|
||||
self.expected_chips = 70
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -23,7 +23,7 @@ class M30SPlusV10(WhatsMiner): # 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 = "M30S+ V10"
|
||||
self.raw_model = "M30S+ V10"
|
||||
self.expected_chips = 215
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -32,7 +32,7 @@ class M30SPlusV20(WhatsMiner): # 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 = "M30S+ V20"
|
||||
self.raw_model = "M30S+ V20"
|
||||
self.expected_chips = 255
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -41,7 +41,7 @@ class M30SPlusV30(WhatsMiner): # 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 = "M30S+ V30"
|
||||
self.raw_model = "M30S+ V30"
|
||||
self.expected_chips = 0
|
||||
warnings.warn(
|
||||
"Unknown chip count for miner type M30S+ V30, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
||||
@@ -53,7 +53,7 @@ class M30SPlusV40(WhatsMiner): # 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 = "M30S+ V40"
|
||||
self.raw_model = "M30S+ V40"
|
||||
self.expected_chips = 235
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -62,7 +62,7 @@ class M30SPlusV50(WhatsMiner): # 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 = "M30S+ V50"
|
||||
self.raw_model = "M30S+ V50"
|
||||
self.expected_chips = 225
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -71,7 +71,7 @@ class M30SPlusV60(WhatsMiner): # 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 = "M30S+ V60"
|
||||
self.raw_model = "M30S+ V60"
|
||||
self.expected_chips = 245
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -80,7 +80,7 @@ class M30SPlusV70(WhatsMiner): # 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 = "M30S+ V70"
|
||||
self.raw_model = "M30S+ V70"
|
||||
self.expected_chips = 235
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -89,7 +89,7 @@ class M30SPlusV80(WhatsMiner): # 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 = "M30S+ V80"
|
||||
self.raw_model = "M30S+ V80"
|
||||
self.expected_chips = 245
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -98,7 +98,7 @@ class M30SPlusV90(WhatsMiner): # 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 = "M30S+ V90"
|
||||
self.raw_model = "M30S+ V90"
|
||||
self.expected_chips = 225
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -107,7 +107,7 @@ class M30SPlusV100(WhatsMiner): # 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 = "M30S+ V100"
|
||||
self.raw_model = "M30S+ V100"
|
||||
self.expected_chips = 215
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -116,7 +116,7 @@ class M30SPlusVE30(WhatsMiner): # 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 = "M30S+ VE30"
|
||||
self.raw_model = "M30S+ VE30"
|
||||
self.expected_chips = 148
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -125,7 +125,7 @@ class M30SPlusVE40(WhatsMiner): # 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 = "M30S+ VE40"
|
||||
self.raw_model = "M30S+ VE40"
|
||||
self.expected_chips = 156
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -134,7 +134,7 @@ class M30SPlusVE50(WhatsMiner): # 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 = "M30S+ VE50"
|
||||
self.raw_model = "M30S+ VE50"
|
||||
self.expected_chips = 164
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -143,7 +143,7 @@ class M30SPlusVE60(WhatsMiner): # 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 = "M30S+ VE60"
|
||||
self.raw_model = "M30S+ VE60"
|
||||
self.expected_chips = 172
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -152,7 +152,7 @@ class M30SPlusVE70(WhatsMiner): # 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 = "M30S+ VE70"
|
||||
self.raw_model = "M30S+ VE70"
|
||||
self.expected_chips = 0
|
||||
warnings.warn(
|
||||
"Unknown chip count for miner type M30S+ VE70, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
||||
@@ -164,7 +164,7 @@ class M30SPlusVE80(WhatsMiner): # 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 = "M30S+ VE80"
|
||||
self.raw_model = "M30S+ VE80"
|
||||
self.expected_chips = 0
|
||||
warnings.warn(
|
||||
"Unknown chip count for miner type M30S+ VE80, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
||||
@@ -176,7 +176,7 @@ class M30SPlusVE90(WhatsMiner): # 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 = "M30S+ VE90"
|
||||
self.raw_model = "M30S+ VE90"
|
||||
self.expected_chips = 0
|
||||
warnings.warn(
|
||||
"Unknown chip count for miner type M30S+ VE90, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
||||
@@ -188,7 +188,7 @@ class M30SPlusVE100(WhatsMiner): # 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 = "M30S+ VE100"
|
||||
self.raw_model = "M30S+ VE100"
|
||||
self.expected_chips = 0
|
||||
warnings.warn(
|
||||
"Unknown chip count for miner type M30S+ VE100, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
||||
@@ -200,7 +200,7 @@ class M30SPlusVF20(WhatsMiner): # 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 = "M30S+ VF20"
|
||||
self.raw_model = "M30S+ VF20"
|
||||
self.expected_chips = 111
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -209,7 +209,7 @@ class M30SPlusVF30(WhatsMiner): # 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 = "M30S+ VF30"
|
||||
self.raw_model = "M30S+ VF30"
|
||||
self.expected_chips = 117
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -218,7 +218,7 @@ class M30SPlusVG20(WhatsMiner): # 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 = "M30S+ VG20"
|
||||
self.raw_model = "M30S+ VG20"
|
||||
self.expected_chips = 82
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -227,7 +227,7 @@ class M30SPlusVG30(WhatsMiner): # 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 = "M30S+ VG30"
|
||||
self.raw_model = "M30S+ VG30"
|
||||
self.expected_chips = 78
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -236,7 +236,7 @@ class M30SPlusVG40(WhatsMiner): # 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 = "M30S+ VG40"
|
||||
self.raw_model = "M30S+ VG40"
|
||||
self.expected_chips = 105
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -245,7 +245,7 @@ class M30SPlusVG50(WhatsMiner): # 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 = "M30S+ VG50"
|
||||
self.raw_model = "M30S+ VG50"
|
||||
self.expected_chips = 111
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -254,7 +254,7 @@ class M30SPlusVG60(WhatsMiner): # 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 = "M30S+ VG60"
|
||||
self.raw_model = "M30S+ VG60"
|
||||
self.expected_chips = 86
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -263,7 +263,7 @@ class M30SPlusVH10(WhatsMiner): # 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 = "M30S+ VH10"
|
||||
self.raw_model = "M30S+ VH10"
|
||||
self.expected_chips = 64
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -272,7 +272,7 @@ class M30SPlusVH20(WhatsMiner): # 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 = "M30S+ VH20"
|
||||
self.raw_model = "M30S+ VH20"
|
||||
self.expected_chips = 66
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -281,7 +281,7 @@ class M30SPlusVH30(WhatsMiner): # 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 = "M30S+ VH30"
|
||||
self.raw_model = "M30S+ VH30"
|
||||
self.expected_chips = 70
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -290,7 +290,7 @@ class M30SPlusVH40(WhatsMiner): # 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 = "M30S+ VH40"
|
||||
self.raw_model = "M30S+ VH40"
|
||||
self.expected_chips = 74
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -299,7 +299,7 @@ class M30SPlusVH50(WhatsMiner): # 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 = "M30S+ VH50"
|
||||
self.raw_model = "M30S+ VH50"
|
||||
self.expected_chips = 64
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -308,6 +308,6 @@ class M30SPlusVH60(WhatsMiner): # 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 = "M30S+ VH60"
|
||||
self.raw_model = "M30S+ VH60"
|
||||
self.expected_chips = 66
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -23,7 +23,7 @@ class M30SPlusPlusV10(WhatsMiner): # 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 = "M30S++ V10"
|
||||
self.raw_model = "M30S++ V10"
|
||||
self.expected_hashboards = 4
|
||||
self.expected_chips = 255
|
||||
self.fan_count = 2
|
||||
@@ -33,7 +33,7 @@ class M30SPlusPlusV20(WhatsMiner): # 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 = "M30S++ V20"
|
||||
self.raw_model = "M30S++ V20"
|
||||
self.expected_hashboards = 4
|
||||
self.expected_chips = 255
|
||||
self.fan_count = 2
|
||||
@@ -43,7 +43,7 @@ class M30SPlusPlusVE30(WhatsMiner): # 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 = "M30S++ VE30"
|
||||
self.raw_model = "M30S++ VE30"
|
||||
self.expected_chips = 215
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -52,7 +52,7 @@ class M30SPlusPlusVE40(WhatsMiner): # 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 = "M30S++ VE40"
|
||||
self.raw_model = "M30S++ VE40"
|
||||
self.expected_chips = 225
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -61,7 +61,7 @@ class M30SPlusPlusVE50(WhatsMiner): # 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 = "M30S++ VE50"
|
||||
self.raw_model = "M30S++ VE50"
|
||||
self.expected_chips = 235
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -70,7 +70,7 @@ class M30SPlusPlusVF40(WhatsMiner): # 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 = "M30S++ VF40"
|
||||
self.raw_model = "M30S++ VF40"
|
||||
self.expected_chips = 156
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -79,7 +79,7 @@ class M30SPlusPlusVG30(WhatsMiner): # 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 = "M30S++ VG30"
|
||||
self.raw_model = "M30S++ VG30"
|
||||
self.expected_chips = 111
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -88,7 +88,7 @@ class M30SPlusPlusVG40(WhatsMiner): # 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 = "M30S++ VG40"
|
||||
self.raw_model = "M30S++ VG40"
|
||||
self.expected_chips = 117
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -97,7 +97,7 @@ class M30SPlusPlusVG50(WhatsMiner): # 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 = "M30S++ VG50"
|
||||
self.raw_model = "M30S++ VG50"
|
||||
self.expected_chips = 0
|
||||
warnings.warn(
|
||||
"Unknown chip count for miner type M30S++ VG50, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
||||
@@ -109,7 +109,7 @@ class M30SPlusPlusVH10(WhatsMiner): # 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 = "M30S++ VH10"
|
||||
self.raw_model = "M30S++ VH10"
|
||||
self.expected_chips = 82
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -118,7 +118,7 @@ class M30SPlusPlusVH20(WhatsMiner): # 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 = "M30S++ VH20"
|
||||
self.raw_model = "M30S++ VH20"
|
||||
self.expected_chips = 86
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -127,7 +127,7 @@ class M30SPlusPlusVH30(WhatsMiner): # 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 = "M30S++ VH30"
|
||||
self.raw_model = "M30S++ VH30"
|
||||
self.expected_chips = 111
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -136,7 +136,7 @@ class M30SPlusPlusVH40(WhatsMiner): # 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 = "M30S++ VH40"
|
||||
self.raw_model = "M30S++ VH40"
|
||||
self.expected_chips = 70
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -145,7 +145,7 @@ class M30SPlusPlusVH50(WhatsMiner): # 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 = "M30S++ VH50"
|
||||
self.raw_model = "M30S++ VH50"
|
||||
self.expected_chips = 74
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -154,7 +154,7 @@ class M30SPlusPlusVH60(WhatsMiner): # 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 = "M30S++ VH60"
|
||||
self.raw_model = "M30S++ VH60"
|
||||
self.expected_chips = 78
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -163,7 +163,7 @@ class M30SPlusPlusVH70(WhatsMiner): # 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 = "M30S++ VH70"
|
||||
self.raw_model = "M30S++ VH70"
|
||||
self.expected_chips = 70
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -172,7 +172,7 @@ class M30SPlusPlusVH80(WhatsMiner): # 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 = "M30S++ VH80"
|
||||
self.raw_model = "M30S++ VH80"
|
||||
self.expected_chips = 74
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -181,7 +181,7 @@ class M30SPlusPlusVH90(WhatsMiner): # 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 = "M30S++ VH90"
|
||||
self.raw_model = "M30S++ VH90"
|
||||
self.expected_chips = 78
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -190,7 +190,7 @@ class M30SPlusPlusVH100(WhatsMiner): # 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 = "M30S++ VH100"
|
||||
self.raw_model = "M30S++ VH100"
|
||||
self.expected_chips = 82
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -199,7 +199,7 @@ class M30SPlusPlusVJ20(WhatsMiner): # 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 = "M30S++ VJ20"
|
||||
self.raw_model = "M30S++ VJ20"
|
||||
self.expected_chips = 0
|
||||
warnings.warn(
|
||||
"Unknown chip count for miner type M30S++ VJ20, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
||||
@@ -211,7 +211,7 @@ class M30SPlusPlusVJ30(WhatsMiner): # 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 = "M30S++ VJ30"
|
||||
self.raw_model = "M30S++ VJ30"
|
||||
self.expected_chips = 0
|
||||
warnings.warn(
|
||||
"Unknown chip count for miner type M30S++ VJ30, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
import warnings
|
||||
|
||||
from pyasic.miners.makes import WhatsMiner
|
||||
|
||||
|
||||
@@ -23,7 +21,7 @@ class M31V10(WhatsMiner): # 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 = "M31 V10"
|
||||
self.raw_model = "M31 V10"
|
||||
self.expected_chips = 70
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -32,6 +30,6 @@ class M31V20(WhatsMiner): # 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 = "M31 V20"
|
||||
self.raw_model = "M31 V20"
|
||||
self.expected_chips = 74
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
import warnings
|
||||
|
||||
from pyasic.miners.makes import WhatsMiner
|
||||
|
||||
|
||||
@@ -23,7 +21,7 @@ class M31HV10(WhatsMiner): # 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 = "M31H V10"
|
||||
self.raw_model = "M31H V10"
|
||||
self.expected_chips = 114
|
||||
self.fan_count = 0
|
||||
|
||||
@@ -32,7 +30,7 @@ class M31HV40(WhatsMiner): # 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 = "M31H V40"
|
||||
self.raw_model = "M31H V40"
|
||||
self.expected_hashboards = 4
|
||||
self.expected_chips = 136
|
||||
self.fan_count = 0
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
import warnings
|
||||
|
||||
from pyasic.miners.makes import WhatsMiner
|
||||
|
||||
|
||||
@@ -23,6 +21,6 @@ class M31LV10(WhatsMiner): # 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 = "M31L V10"
|
||||
self.raw_model = "M31L V10"
|
||||
self.expected_chips = 114
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -23,7 +23,7 @@ class M31SV10(WhatsMiner): # 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 = "M31S V10"
|
||||
self.raw_model = "M31S V10"
|
||||
self.expected_chips = 105
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -32,7 +32,7 @@ class M31SV20(WhatsMiner): # 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 = "M31S V20"
|
||||
self.raw_model = "M31S V20"
|
||||
self.expected_chips = 111
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -41,7 +41,7 @@ class M31SV30(WhatsMiner): # 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 = "M31S V30"
|
||||
self.raw_model = "M31S V30"
|
||||
self.expected_chips = 117
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -50,7 +50,7 @@ class M31SV40(WhatsMiner): # 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 = "M31S V40"
|
||||
self.raw_model = "M31S V40"
|
||||
self.expected_chips = 123
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -59,7 +59,7 @@ class M31SV50(WhatsMiner): # 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 = "M31S V50"
|
||||
self.raw_model = "M31S V50"
|
||||
self.expected_chips = 78
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -68,7 +68,7 @@ class M31SV60(WhatsMiner): # 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 = "M31S V60"
|
||||
self.raw_model = "M31S V60"
|
||||
self.expected_chips = 105
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -77,7 +77,7 @@ class M31SV70(WhatsMiner): # 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 = "M31S V70"
|
||||
self.raw_model = "M31S V70"
|
||||
self.expected_chips = 111
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -86,7 +86,7 @@ class M31SV80(WhatsMiner): # 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 = "M31S V80"
|
||||
self.raw_model = "M31S V80"
|
||||
self.expected_chips = 0
|
||||
warnings.warn(
|
||||
"Unknown chip count for miner type M31SV80, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
||||
@@ -98,7 +98,7 @@ class M31SV90(WhatsMiner): # 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 = "M31S V90"
|
||||
self.raw_model = "M31S V90"
|
||||
self.expected_chips = 117
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -107,7 +107,7 @@ class M31SVE10(WhatsMiner): # 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 = "M31S VE10"
|
||||
self.raw_model = "M31S VE10"
|
||||
self.expected_chips = 70
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -116,7 +116,7 @@ class M31SVE20(WhatsMiner): # 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 = "M31S VE20"
|
||||
self.raw_model = "M31S VE20"
|
||||
self.expected_chips = 74
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -125,7 +125,7 @@ class M31SVE30(WhatsMiner): # 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 = "M31S VE30"
|
||||
self.raw_model = "M31S VE30"
|
||||
self.expected_chips = 0
|
||||
warnings.warn(
|
||||
"Unknown chip count for miner type M31SVE30, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
import warnings
|
||||
|
||||
from pyasic.miners.makes import WhatsMiner
|
||||
|
||||
|
||||
@@ -23,7 +21,7 @@ class M31SEV10(WhatsMiner): # 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 = "M31SE V10"
|
||||
self.raw_model = "M31SE V10"
|
||||
self.expected_chips = 82
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -32,7 +30,7 @@ class M31SEV20(WhatsMiner): # 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 = "M31SE V20"
|
||||
self.raw_model = "M31SE V20"
|
||||
self.expected_chips = 78
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -41,6 +39,6 @@ class M31SEV30(WhatsMiner): # 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 = "M31SE V30"
|
||||
self.raw_model = "M31SE V30"
|
||||
self.expected_chips = 78
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -23,7 +23,7 @@ class M31SPlusV10(WhatsMiner): # 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 = "M31S+ V10"
|
||||
self.raw_model = "M31S+ V10"
|
||||
self.expected_chips = 105
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -32,7 +32,7 @@ class M31SPlusV20(WhatsMiner): # 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 = "M31S+ V20"
|
||||
self.raw_model = "M31S+ V20"
|
||||
self.expected_chips = 111
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -41,7 +41,7 @@ class M31SPlusV30(WhatsMiner): # 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 = "M31S+ V30"
|
||||
self.raw_model = "M31S+ V30"
|
||||
self.expected_chips = 117
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -50,7 +50,7 @@ class M31SPlusV40(WhatsMiner): # 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 = "M31S+ V40"
|
||||
self.raw_model = "M31S+ V40"
|
||||
self.expected_chips = 123
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -59,7 +59,7 @@ class M31SPlusV50(WhatsMiner): # 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 = "M31S+ V50"
|
||||
self.raw_model = "M31S+ V50"
|
||||
self.expected_chips = 148
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -68,7 +68,7 @@ class M31SPlusV60(WhatsMiner): # 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 = "M31S+ V60"
|
||||
self.raw_model = "M31S+ V60"
|
||||
self.expected_chips = 156
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -77,7 +77,7 @@ class M31SPlusV80(WhatsMiner): # 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 = "M31S+ V80"
|
||||
self.raw_model = "M31S+ V80"
|
||||
self.expected_chips = 129
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -86,7 +86,7 @@ class M31SPlusV90(WhatsMiner): # 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 = "M31S+ V90"
|
||||
self.raw_model = "M31S+ V90"
|
||||
self.expected_chips = 117
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -95,7 +95,7 @@ class M31SPlusV100(WhatsMiner): # 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 = "M31S+ V100"
|
||||
self.raw_model = "M31S+ V100"
|
||||
self.expected_chips = 111
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -104,7 +104,7 @@ class M31SPlusVE10(WhatsMiner): # 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 = "M31S+ VE10"
|
||||
self.raw_model = "M31S+ VE10"
|
||||
self.expected_chips = 82
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -113,7 +113,7 @@ class M31SPlusVE20(WhatsMiner): # 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 = "M31S+ VE20"
|
||||
self.raw_model = "M31S+ VE20"
|
||||
self.expected_chips = 78
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -122,7 +122,7 @@ class M31SPlusVE30(WhatsMiner): # 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 = "M31S+ VE30"
|
||||
self.raw_model = "M31S+ VE30"
|
||||
self.expected_chips = 105
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -131,7 +131,7 @@ class M31SPlusVE40(WhatsMiner): # 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 = "M31S+ VE40"
|
||||
self.raw_model = "M31S+ VE40"
|
||||
self.expected_chips = 111
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -140,7 +140,7 @@ class M31SPlusVE50(WhatsMiner): # 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 = "M31S+ VE50"
|
||||
self.raw_model = "M31S+ VE50"
|
||||
self.expected_chips = 117
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -149,7 +149,7 @@ class M31SPlusVE60(WhatsMiner): # 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 = "M31S+ VE60"
|
||||
self.raw_model = "M31S+ VE60"
|
||||
self.expected_chips = 0
|
||||
warnings.warn(
|
||||
"Unknown chip count for miner type M30S+ VE60, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
||||
@@ -161,7 +161,7 @@ class M31SPlusVE80(WhatsMiner): # 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 = "M31S+ VE80"
|
||||
self.raw_model = "M31S+ VE80"
|
||||
self.expected_chips = 0
|
||||
warnings.warn(
|
||||
"Unknown chip count for miner type M30S+ VE80, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
||||
@@ -173,7 +173,7 @@ class M31SPlusVF20(WhatsMiner): # 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 = "M31S+ VF20"
|
||||
self.raw_model = "M31S+ VF20"
|
||||
self.expected_chips = 66
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -182,7 +182,7 @@ class M31SPlusVF30(WhatsMiner): # 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 = "M31S+ VF30"
|
||||
self.raw_model = "M31S+ VF30"
|
||||
self.expected_chips = 0
|
||||
warnings.warn(
|
||||
"Unknown chip count for miner type M30S+ VF30, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
||||
@@ -194,7 +194,7 @@ class M31SPlusVG20(WhatsMiner): # 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 = "M31S+ VG20"
|
||||
self.raw_model = "M31S+ VG20"
|
||||
self.expected_chips = 66
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -203,7 +203,7 @@ class M31SPlusVG30(WhatsMiner): # 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 = "M31S+ VG30"
|
||||
self.raw_model = "M31S+ VG30"
|
||||
self.expected_chips = 70
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -212,7 +212,7 @@ class M31SPlusV30(WhatsMiner): # 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 = "M31S+ V30"
|
||||
self.raw_model = "M31S+ V30"
|
||||
self.expected_chips = 117
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -221,6 +221,6 @@ class M31SPlusV40(WhatsMiner): # 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 = "M31S+ V40"
|
||||
self.raw_model = "M31S+ V40"
|
||||
self.expected_chips = 123
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
import warnings
|
||||
|
||||
from pyasic.miners.makes import WhatsMiner
|
||||
|
||||
|
||||
@@ -23,7 +21,7 @@ class M32V10(WhatsMiner): # 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 = "M32 V10"
|
||||
self.raw_model = "M32 V10"
|
||||
self.expected_chips = 78
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -32,6 +30,6 @@ class M32V20(WhatsMiner): # 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 = "M32 V20"
|
||||
self.raw_model = "M32 V20"
|
||||
self.expected_chips = 74
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -21,6 +21,6 @@ class M32S(WhatsMiner): # 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 = "M32S"
|
||||
self.raw_model = "M32S"
|
||||
self.expected_chips = 78
|
||||
self.fan_count = 2
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
import warnings
|
||||
|
||||
from pyasic.miners.makes import WhatsMiner
|
||||
|
||||
|
||||
@@ -23,7 +21,7 @@ class M33V10(WhatsMiner): # 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 = "M33 V10"
|
||||
self.raw_model = "M33 V10"
|
||||
self.expected_chips = 33
|
||||
self.fan_count = 0
|
||||
|
||||
@@ -32,7 +30,7 @@ class M33V20(WhatsMiner): # 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 = "M33 V20"
|
||||
self.raw_model = "M33 V20"
|
||||
self.expected_chips = 62
|
||||
self.fan_count = 0
|
||||
|
||||
@@ -41,6 +39,6 @@ class M33V30(WhatsMiner): # 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 = "M33 V30"
|
||||
self.raw_model = "M33 V30"
|
||||
self.expected_chips = 66
|
||||
self.fan_count = 0
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
import warnings
|
||||
|
||||
from pyasic.miners.makes import WhatsMiner
|
||||
|
||||
|
||||
@@ -23,7 +21,7 @@ class M33SVG30(WhatsMiner): # 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 = "M33S VG30"
|
||||
self.raw_model = "M33S VG30"
|
||||
self.expected_hashboards = 4
|
||||
self.expected_chips = 116
|
||||
self.fan_count = 0
|
||||
|
||||
@@ -23,7 +23,7 @@ class M33SPlusVG20(WhatsMiner): # 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 = "M33S+ VG20"
|
||||
self.raw_model = "M33S+ VG20"
|
||||
self.expected_hashboards = 4
|
||||
self.expected_chips = 112
|
||||
self.fan_count = 0
|
||||
@@ -33,7 +33,7 @@ class M33SPlusVH20(WhatsMiner): # 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 = "M33S+ VH20"
|
||||
self.raw_model = "M33S+ VH20"
|
||||
self.expected_hashboards = 4
|
||||
self.expected_chips = 100
|
||||
self.fan_count = 0
|
||||
@@ -43,7 +43,7 @@ class M33SPlusVH30(WhatsMiner): # 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 = "M33S+ VH30"
|
||||
self.raw_model = "M33S+ VH30"
|
||||
self.expected_hashboards = 4
|
||||
self.expected_chips = 0 # slot1 116, slot2 106, slot3 116, slot4 106
|
||||
warnings.warn(
|
||||
|
||||
@@ -23,7 +23,7 @@ class M33SPlusPlusVH20(WhatsMiner): # 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 = "M33S++ VH20"
|
||||
self.raw_model = "M33S++ VH20"
|
||||
self.expected_hashboards = 4
|
||||
self.expected_chips = 112
|
||||
self.fan_count = 0
|
||||
@@ -33,7 +33,7 @@ class M33SPlusPlusVH30(WhatsMiner): # 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 = "M33S++ VH30"
|
||||
self.raw_model = "M33S++ VH30"
|
||||
self.expected_hashboards = 4
|
||||
self.expected_chips = 0
|
||||
warnings.warn(
|
||||
@@ -46,7 +46,7 @@ class M33SPlusPlusVG40(WhatsMiner): # 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 = "M33S++ VG40"
|
||||
self.raw_model = "M33S++ VG40"
|
||||
self.expected_hashboards = 4
|
||||
self.expected_chips = 174
|
||||
self.fan_count = 0
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user