Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e7f05f7a28 | ||
|
|
2d229be9fd | ||
|
|
de5038e57a | ||
|
|
8ad1b3f72a | ||
|
|
070fb26dbc | ||
|
|
80d9d7df1d | ||
|
|
928c24f56f | ||
|
|
6e7442f90d | ||
|
|
936474ed3b | ||
|
|
2e28060e05 | ||
|
|
07f92557c6 | ||
|
|
6f6f5743cf |
@@ -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",
|
||||
|
||||
@@ -161,6 +161,15 @@ class MinerConfig:
|
||||
power_scaling=PowerScalingConfig.from_bosminer(toml_conf),
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_epic(cls, web_conf: dict) -> "MinerConfig":
|
||||
return cls(
|
||||
pools=PoolConfig.from_epic(web_conf),
|
||||
fan_mode=FanModeConfig.from_epic(web_conf),
|
||||
temperature=TemperatureConfig.from_epic(web_conf),
|
||||
mining_mode=MiningModeConfig.from_epic(web_conf),
|
||||
)
|
||||
|
||||
|
||||
def merge(a: dict, b: dict) -> dict:
|
||||
result = deepcopy(a)
|
||||
|
||||
@@ -116,6 +116,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:
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
# 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
|
||||
|
||||
@@ -132,7 +132,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":
|
||||
@@ -186,6 +186,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:
|
||||
|
||||
@@ -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(
|
||||
@@ -138,7 +144,7 @@ class Pool(MinerConfigValue):
|
||||
|
||||
@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 +243,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 = []
|
||||
@@ -265,7 +278,7 @@ class PoolGroup(MinerConfigValue):
|
||||
|
||||
@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 +292,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):
|
||||
@@ -329,11 +342,19 @@ class PoolConfig(MinerConfigValue):
|
||||
|
||||
@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"]
|
||||
|
||||
@@ -56,3 +56,18 @@ 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)
|
||||
|
||||
@@ -48,6 +48,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):
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
import asyncio
|
||||
from typing import List, Optional, Union
|
||||
|
||||
from pyasic.API import APIError
|
||||
@@ -23,50 +22,60 @@ from pyasic.data import Fan, HashBoard
|
||||
from pyasic.data.error_codes import MinerErrorData, X19Error
|
||||
from pyasic.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.MODEL): DataFunction("get_model"),
|
||||
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):
|
||||
@@ -185,6 +194,42 @@ class AntminerModern(BMMiner):
|
||||
pass
|
||||
return errors
|
||||
|
||||
async def get_hashboards(self) -> List[HashBoard]:
|
||||
hashboards = [
|
||||
HashBoard(idx, expected_chips=self.expected_chips)
|
||||
for idx in range(self.expected_hashboards)
|
||||
]
|
||||
|
||||
try:
|
||||
api_stats = await self.api.send_command("stats", new_api=True)
|
||||
except APIError:
|
||||
return hashboards
|
||||
|
||||
if api_stats:
|
||||
try:
|
||||
for board in api_stats["STATS"][0]["chain"]:
|
||||
hashboards[board["index"]].hashrate = round(
|
||||
board["rate_real"] / 1000, 2
|
||||
)
|
||||
hashboards[board["index"]].chips = board["asic_num"]
|
||||
board_temp_data = list(
|
||||
filter(lambda x: not x == 0, board["temp_pcb"])
|
||||
)
|
||||
hashboards[board["index"]].temp = sum(board_temp_data) / len(
|
||||
board_temp_data
|
||||
)
|
||||
chip_temp_data = list(
|
||||
filter(lambda x: not x == 0, board["temp_chip"])
|
||||
)
|
||||
hashboards[board["index"]].chip_temp = sum(chip_temp_data) / len(
|
||||
chip_temp_data
|
||||
)
|
||||
hashboards[board["index"]].serial_number = board["sn"]
|
||||
hashboards[board["index"]].missing = False
|
||||
except LookupError:
|
||||
pass
|
||||
return hashboards
|
||||
|
||||
async def get_fault_light(self, web_get_blink_status: dict = None) -> bool:
|
||||
if self.light:
|
||||
return self.light
|
||||
@@ -298,39 +343,49 @@ 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.MODEL): DataFunction("get_model"),
|
||||
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):
|
||||
|
||||
@@ -22,32 +22,48 @@ 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.MODEL): DataFunction("get_model"),
|
||||
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):
|
||||
@@ -268,32 +284,6 @@ class BFGMiner(BaseMiner):
|
||||
|
||||
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]:
|
||||
return []
|
||||
|
||||
|
||||
@@ -20,41 +20,55 @@ 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.MODEL): DataFunction("get_model"),
|
||||
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):
|
||||
|
||||
@@ -23,32 +23,50 @@ 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.MODEL): DataFunction("get_model"),
|
||||
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):
|
||||
@@ -315,32 +333,6 @@ class BMMiner(BaseMiner):
|
||||
|
||||
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]:
|
||||
return []
|
||||
|
||||
|
||||
@@ -27,157 +27,157 @@ from pyasic.config.mining import MiningModePowerTune
|
||||
from pyasic.data import Fan, HashBoard
|
||||
from pyasic.data.error_codes import BraiinsOSError, MinerErrorData
|
||||
from pyasic.errors import APIError
|
||||
from pyasic.miners.base import BaseMiner
|
||||
from pyasic.miners.base import (
|
||||
BaseMiner,
|
||||
DataFunction,
|
||||
DataLocations,
|
||||
DataOptions,
|
||||
GraphQLCommand,
|
||||
RPCAPICommand,
|
||||
WebAPICommand,
|
||||
)
|
||||
from pyasic.web.bosminer import BOSMinerWebAPI
|
||||
|
||||
BOSMINER_DATA_LOC = {
|
||||
"mac": {
|
||||
"cmd": "get_mac",
|
||||
"kwargs": {
|
||||
"web_net_conf": {"web": "/cgi-bin/luci/admin/network/iface_status/lan"}
|
||||
},
|
||||
},
|
||||
"model": {"cmd": "get_model", "kwargs": {}},
|
||||
"api_ver": {"cmd": "get_api_ver", "kwargs": {"api_version": {"api": "version"}}},
|
||||
"fw_ver": {
|
||||
"cmd": "get_fw_ver",
|
||||
"kwargs": {
|
||||
"graphql_version": {"web": {"bos": {"info": {"version": {"full": None}}}}}
|
||||
},
|
||||
},
|
||||
"hostname": {
|
||||
"cmd": "get_hostname",
|
||||
"kwargs": {"graphql_hostname": {"web": {"bos": {"hostname": None}}}},
|
||||
},
|
||||
"hashrate": {
|
||||
"cmd": "get_hashrate",
|
||||
"kwargs": {
|
||||
"api_summary": {"api": "summary"},
|
||||
"graphql_hashrate": {
|
||||
"web": {
|
||||
"bosminer": {
|
||||
"info": {"workSolver": {"realHashrate": {"mhs1M": None}}}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"expected_hashrate": {
|
||||
"cmd": "get_expected_hashrate",
|
||||
"kwargs": {"api_devs": {"api": "devs"}},
|
||||
},
|
||||
"hashboards": {
|
||||
"cmd": "get_hashboards",
|
||||
"kwargs": {
|
||||
"api_temps": {"api": "temps"},
|
||||
"api_devdetails": {"api": "devdetails"},
|
||||
"api_devs": {"api": "devs"},
|
||||
"graphql_boards": {
|
||||
"web": {
|
||||
"bosminer": {
|
||||
"info": {
|
||||
"workSolver": {
|
||||
"childSolvers": {
|
||||
"name": None,
|
||||
"realHashrate": {"mhs1M": None},
|
||||
"hwDetails": {"chips": None},
|
||||
"temperatures": {"degreesC": None},
|
||||
BOSMINER_DATA_LOC = DataLocations(
|
||||
**{
|
||||
str(DataOptions.MAC): DataFunction(
|
||||
"get_mac",
|
||||
[
|
||||
WebAPICommand(
|
||||
"web_net_conf", "/cgi-bin/luci/admin/network/iface_status/lan"
|
||||
)
|
||||
],
|
||||
),
|
||||
str(DataOptions.MODEL): DataFunction("get_model"),
|
||||
str(DataOptions.API_VERSION): DataFunction(
|
||||
"get_api_ver", [RPCAPICommand("api_version", "version")]
|
||||
),
|
||||
str(DataOptions.FW_VERSION): DataFunction(
|
||||
"get_fw_ver",
|
||||
[
|
||||
GraphQLCommand(
|
||||
"graphql_version", {"bos": {"info": {"version": {"full": None}}}}
|
||||
)
|
||||
],
|
||||
),
|
||||
str(DataOptions.HOSTNAME): DataFunction(
|
||||
"get_hostname",
|
||||
[GraphQLCommand("graphql_hostname", {"bos": {"hostname": None}})],
|
||||
),
|
||||
str(DataOptions.HASHRATE): DataFunction(
|
||||
"get_hashrate",
|
||||
[
|
||||
RPCAPICommand("api_summary", "summary"),
|
||||
GraphQLCommand(
|
||||
"graphql_hashrate",
|
||||
{
|
||||
"bosminer": {
|
||||
"info": {"workSolver": {"realHashrate": {"mhs1M": None}}}
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
|
||||
"get_expected_hashrate", [RPCAPICommand("api_devs", "devs")]
|
||||
),
|
||||
str(DataOptions.HASHBOARDS): DataFunction(
|
||||
"get_hashboards",
|
||||
[
|
||||
RPCAPICommand("api_temps", "temps"),
|
||||
RPCAPICommand("api_devdetails", "devdetails"),
|
||||
RPCAPICommand("api_devs", "devs"),
|
||||
GraphQLCommand(
|
||||
"graphql_boards",
|
||||
{
|
||||
"bosminer": {
|
||||
"info": {
|
||||
"workSolver": {
|
||||
"childSolvers": {
|
||||
"name": None,
|
||||
"realHashrate": {"mhs1M": None},
|
||||
"hwDetails": {"chips": None},
|
||||
"temperatures": {"degreesC": None},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"wattage": {
|
||||
"cmd": "get_wattage",
|
||||
"kwargs": {
|
||||
"api_tunerstatus": {"api": "tunerstatus"},
|
||||
"graphql_wattage": {
|
||||
"web": {
|
||||
"bosminer": {
|
||||
"info": {"workSolver": {"power": {"approxConsumptionW": None}}}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
"wattage_limit": {
|
||||
"cmd": "get_wattage_limit",
|
||||
"kwargs": {
|
||||
"api_tunerstatus": {"api": "tunerstatus"},
|
||||
"graphql_wattage_limit": {
|
||||
"web": {
|
||||
"bosminer": {"info": {"workSolver": {"power": {"limitW": None}}}}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
"fans": {
|
||||
"cmd": "get_fans",
|
||||
"kwargs": {
|
||||
"api_fans": {"api": "fans"},
|
||||
"graphql_fans": {
|
||||
"web": {"bosminer": {"info": {"fans": {"name": None, "rpm": None}}}}
|
||||
},
|
||||
},
|
||||
},
|
||||
"fan_psu": {"cmd": "get_fan_psu", "kwargs": {}},
|
||||
"env_temp": {"cmd": "get_env_temp", "kwargs": {}},
|
||||
"errors": {
|
||||
"cmd": "get_errors",
|
||||
"kwargs": {
|
||||
"api_tunerstatus": {"api": "tunerstatus"},
|
||||
"graphql_errors": {
|
||||
"web": {
|
||||
"bosminer": {
|
||||
"info": {
|
||||
"workSolver": {
|
||||
"childSolvers": {
|
||||
"name": None,
|
||||
"tuner": {"statusMessages": None},
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
str(DataOptions.ENVIRONMENT_TEMP): DataFunction("get_env_temp"),
|
||||
str(DataOptions.WATTAGE): DataFunction(
|
||||
"get_wattage",
|
||||
[
|
||||
RPCAPICommand("api_tunerstatus", "tunerstatus"),
|
||||
GraphQLCommand(
|
||||
"graphql_wattage",
|
||||
{
|
||||
"bosminer": {
|
||||
"info": {
|
||||
"workSolver": {"power": {"approxConsumptionW": None}}
|
||||
}
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
str(DataOptions.WATTAGE_LIMIT): DataFunction(
|
||||
"get_wattage_limit",
|
||||
[
|
||||
RPCAPICommand("api_tunerstatus", "tunerstatus"),
|
||||
GraphQLCommand(
|
||||
"graphql_wattage_limit",
|
||||
{"bosminer": {"info": {"workSolver": {"power": {"limitW": None}}}}},
|
||||
),
|
||||
],
|
||||
),
|
||||
str(DataOptions.FANS): DataFunction(
|
||||
"get_fans",
|
||||
[
|
||||
RPCAPICommand("api_fans", "fans"),
|
||||
GraphQLCommand(
|
||||
"graphql_fans",
|
||||
{"bosminer": {"info": {"fans": {"name": None, "rpm": None}}}},
|
||||
),
|
||||
],
|
||||
),
|
||||
str(DataOptions.FAN_PSU): DataFunction("get_fan_psu"),
|
||||
str(DataOptions.ERRORS): DataFunction(
|
||||
"get_errors",
|
||||
[
|
||||
RPCAPICommand("api_tunerstatus", "tunerstatus"),
|
||||
GraphQLCommand(
|
||||
"graphql_errors",
|
||||
{
|
||||
"bosminer": {
|
||||
"info": {
|
||||
"workSolver": {
|
||||
"childSolvers": {
|
||||
"name": None,
|
||||
"tuner": {"statusMessages": None},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
"fault_light": {
|
||||
"cmd": "get_fault_light",
|
||||
"kwargs": {"graphql_fault_light": {"web": {"bos": {"faultLight": None}}}},
|
||||
},
|
||||
"pools": {
|
||||
"cmd": "get_pools",
|
||||
"kwargs": {
|
||||
"api_pools": {"api": "pools"},
|
||||
"graphql_pools": {
|
||||
"web": {
|
||||
"bosminer": {
|
||||
"config": {
|
||||
"... on BosminerConfig": {
|
||||
"groups": {
|
||||
"pools": {"url": None, "user": None},
|
||||
"strategy": {
|
||||
"... on QuotaStrategy": {"quota": None}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
"is_mining": {
|
||||
"cmd": "is_mining",
|
||||
"kwargs": {"api_devdetails": {"api": "devdetails"}},
|
||||
},
|
||||
"uptime": {"cmd": "get_uptime", "kwargs": {"api_summary": {"api": "summary"}}},
|
||||
"config": {"cmd": "get_config", "kwargs": {}},
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
str(DataOptions.FAULT_LIGHT): DataFunction(
|
||||
"get_fault_light",
|
||||
[GraphQLCommand("graphql_fault_light", {"bos": {"faultLight": None}})],
|
||||
),
|
||||
str(DataOptions.IS_MINING): DataFunction(
|
||||
"is_mining", [RPCAPICommand("api_devdetails", "devdetails")]
|
||||
),
|
||||
str(DataOptions.UPTIME): DataFunction(
|
||||
"get_uptime", [RPCAPICommand("api_summary", "summary")]
|
||||
),
|
||||
str(DataOptions.CONFIG): DataFunction("get_config"),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
class BOSMiner(BaseMiner):
|
||||
@@ -231,7 +231,6 @@ class BOSMiner(BaseMiner):
|
||||
return result
|
||||
|
||||
async def fault_light_on(self) -> bool:
|
||||
"""Sends command to turn on fault light on the miner."""
|
||||
logging.debug(f"{self}: Sending fault_light on command.")
|
||||
ret = await self.send_ssh_command("miner fault_light on")
|
||||
logging.debug(f"{self}: fault_light on command completed.")
|
||||
@@ -241,7 +240,6 @@ class BOSMiner(BaseMiner):
|
||||
return False
|
||||
|
||||
async def fault_light_off(self) -> bool:
|
||||
"""Sends command to turn off fault light on the miner."""
|
||||
logging.debug(f"{self}: Sending fault_light off command.")
|
||||
self.light = False
|
||||
ret = await self.send_ssh_command("miner fault_light off")
|
||||
@@ -252,11 +250,9 @@ class BOSMiner(BaseMiner):
|
||||
return False
|
||||
|
||||
async def restart_backend(self) -> bool:
|
||||
"""Restart bosminer hashing process. Wraps [`restart_bosminer`][pyasic.miners.backends.bosminer.BOSMiner.restart_bosminer] to standardize."""
|
||||
return await self.restart_bosminer()
|
||||
|
||||
async def restart_bosminer(self) -> bool:
|
||||
"""Restart bosminer hashing process."""
|
||||
logging.debug(f"{self}: Sending bosminer restart command.")
|
||||
ret = await self.send_ssh_command("/etc/init.d/bosminer restart")
|
||||
logging.debug(f"{self}: bosminer restart command completed.")
|
||||
@@ -285,7 +281,6 @@ class BOSMiner(BaseMiner):
|
||||
return False
|
||||
|
||||
async def reboot(self) -> bool:
|
||||
"""Reboots power to the physical miner."""
|
||||
logging.debug(f"{self}: Sending reboot command.")
|
||||
ret = await self.send_ssh_command("/sbin/reboot")
|
||||
logging.debug(f"{self}: Reboot command completed.")
|
||||
@@ -537,7 +532,7 @@ class BOSMiner(BaseMiner):
|
||||
pass
|
||||
|
||||
try:
|
||||
async with (await self._get_ssh_connection()) as conn:
|
||||
async with await self._get_ssh_connection() as conn:
|
||||
if conn is not None:
|
||||
data = await conn.run("cat /proc/sys/kernel/hostname")
|
||||
host = data.stdout.strip()
|
||||
@@ -833,95 +828,6 @@ class BOSMiner(BaseMiner):
|
||||
async def get_fan_psu(self) -> Optional[int]:
|
||||
return None
|
||||
|
||||
async def get_pools(
|
||||
self, api_pools: dict = None, graphql_pools: dict = None
|
||||
) -> List[dict]:
|
||||
if not graphql_pools and not api_pools:
|
||||
try:
|
||||
graphql_pools = await self.web.send_command(
|
||||
{
|
||||
"bosminer": {
|
||||
"config": {
|
||||
"... on BosminerConfig": {
|
||||
"groups": {
|
||||
"pools": {"urluser"},
|
||||
"strategy": {"... on QuotaStrategy": {"quota"}},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
if graphql_pools:
|
||||
groups = []
|
||||
try:
|
||||
g = graphql_pools["data"]["bosminer"]["config"]["groups"]
|
||||
for group in g:
|
||||
pools = {"quota": group["strategy"]["quota"]}
|
||||
for i, pool in enumerate(group["pools"]):
|
||||
pools[f"pool_{i + 1}_url"] = (
|
||||
pool["url"]
|
||||
.replace("stratum+tcp://", "")
|
||||
.replace("stratum2+tcp://", "")
|
||||
)
|
||||
pools[f"pool_{i + 1}_user"] = pool["user"]
|
||||
groups.append(pools)
|
||||
return groups
|
||||
except (KeyError, TypeError):
|
||||
pass
|
||||
|
||||
if not api_pools:
|
||||
try:
|
||||
api_pools = await self.api.pools()
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
if api_pools:
|
||||
seen = []
|
||||
groups = [{"quota": "0"}]
|
||||
if api_pools.get("POOLS"):
|
||||
for i, pool in enumerate(api_pools["POOLS"]):
|
||||
if len(seen) == 0:
|
||||
seen.append(pool["User"])
|
||||
if not pool["User"] in seen:
|
||||
# need to use get_config, as this will never read perfectly as there are some bad edge cases
|
||||
groups = []
|
||||
cfg = await self.get_config()
|
||||
if cfg:
|
||||
for group in cfg.pool_groups:
|
||||
pools = {"quota": group.quota}
|
||||
for _i, _pool in enumerate(group.pools):
|
||||
pools[f"pool_{_i + 1}_url"] = _pool.url.replace(
|
||||
"stratum+tcp://", ""
|
||||
).replace("stratum2+tcp://", "")
|
||||
pools[f"pool_{_i + 1}_user"] = _pool.username
|
||||
groups.append(pools)
|
||||
return groups
|
||||
else:
|
||||
groups[0][f"pool_{i + 1}_url"] = (
|
||||
pool["URL"]
|
||||
.replace("stratum+tcp://", "")
|
||||
.replace("stratum2+tcp://", "")
|
||||
)
|
||||
groups[0][f"pool_{i + 1}_user"] = pool["User"]
|
||||
else:
|
||||
groups = []
|
||||
cfg = await self.get_config()
|
||||
if cfg:
|
||||
for group in cfg.pool_groups:
|
||||
pools = {"quota": group.quota}
|
||||
for _i, _pool in enumerate(group.pools):
|
||||
pools[f"pool_{_i + 1}_url"] = _pool.url.replace(
|
||||
"stratum+tcp://", ""
|
||||
).replace("stratum2+tcp://", "")
|
||||
pools[f"pool_{_i + 1}_user"] = _pool.username
|
||||
groups.append(pools)
|
||||
return groups
|
||||
return groups
|
||||
|
||||
async def get_errors(
|
||||
self, api_tunerstatus: dict = None, graphql_errors: dict = None
|
||||
) -> List[MinerErrorData]:
|
||||
|
||||
@@ -136,9 +136,6 @@ class BOSMinerOld(BOSMiner):
|
||||
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 []
|
||||
|
||||
|
||||
@@ -23,74 +23,86 @@ 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,
|
||||
WebAPICommand,
|
||||
)
|
||||
|
||||
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.MODEL): DataFunction("get_model"),
|
||||
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")]
|
||||
),
|
||||
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):
|
||||
@@ -434,6 +446,7 @@ 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):
|
||||
pass
|
||||
@@ -529,32 +542,6 @@ 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(
|
||||
self, api_summary: dict = None, api_get_error_code: dict = None
|
||||
) -> List[MinerErrorData]:
|
||||
|
||||
@@ -23,32 +23,50 @@ 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.MODEL): DataFunction("get_model"),
|
||||
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 +112,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 +123,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:
|
||||
@@ -328,32 +343,6 @@ class CGMiner(BaseMiner):
|
||||
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]:
|
||||
return []
|
||||
|
||||
|
||||
@@ -23,37 +23,52 @@ 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.MODEL): DataFunction("get_model"),
|
||||
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", [RPCAPICommand("api_version", "version")]
|
||||
),
|
||||
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 +131,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:
|
||||
@@ -318,32 +333,6 @@ class CGMinerAvalon(CGMiner):
|
||||
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]:
|
||||
return []
|
||||
|
||||
|
||||
@@ -14,51 +14,74 @@
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
from typing import List, Optional, Tuple, Union
|
||||
from typing import List, Optional, Tuple
|
||||
|
||||
from pyasic import MinerConfig
|
||||
from pyasic.data import Fan, HashBoard
|
||||
from pyasic.data.error_codes import MinerErrorData, X19Error
|
||||
from pyasic.config import MinerConfig, MiningModeConfig
|
||||
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.MODEL): DataFunction("get_model"),
|
||||
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
|
||||
@@ -74,6 +97,23 @@ class ePIC(BMMiner):
|
||||
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()
|
||||
if data:
|
||||
@@ -110,13 +150,13 @@ 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"]
|
||||
for network in web_network:
|
||||
mac = web_network[network]["mac_address"]
|
||||
return mac
|
||||
except KeyError:
|
||||
pass
|
||||
@@ -249,32 +289,6 @@ class ePIC(BMMiner):
|
||||
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]:
|
||||
if not web_summary:
|
||||
web_summary = await self.web.summary()
|
||||
@@ -310,3 +324,33 @@ class ePIC(BMMiner):
|
||||
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_config(self) -> MinerConfig:
|
||||
return self.config
|
||||
|
||||
def get_env_temp(self, *args, **kwargs) -> Optional[float]:
|
||||
pass
|
||||
|
||||
def get_fan_psu(self, *args, **kwargs) -> Optional[int]:
|
||||
pass
|
||||
|
||||
def get_version(self, *args, **kwargs) -> Tuple[Optional[str], Optional[str]]:
|
||||
pass
|
||||
|
||||
def get_wattage_limit(self, *args, **kwargs) -> Optional[int]:
|
||||
pass
|
||||
|
||||
def send_config(self, config: MinerConfig, user_suffix: str = None) -> None:
|
||||
pass
|
||||
|
||||
def set_power_limit(self, wattage: int) -> bool:
|
||||
return False
|
||||
|
||||
@@ -26,30 +26,52 @@ from pyasic.config import MinerConfig
|
||||
from pyasic.data import Fan, HashBoard
|
||||
from pyasic.data.error_codes import BraiinsOSError, MinerErrorData
|
||||
from pyasic.errors import APIError
|
||||
from pyasic.miners.base import BaseMiner
|
||||
from pyasic.miners.base import (
|
||||
BaseMiner,
|
||||
DataFunction,
|
||||
DataLocations,
|
||||
DataOptions,
|
||||
RPCAPICommand,
|
||||
WebAPICommand,
|
||||
)
|
||||
from pyasic.web.bosminer import BOSMinerWebAPI
|
||||
|
||||
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.MODEL): DataFunction("get_model"),
|
||||
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):
|
||||
@@ -85,7 +107,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 +117,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 +127,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 +159,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:
|
||||
@@ -303,56 +320,6 @@ class LUXMiner(BaseMiner):
|
||||
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]:
|
||||
pass
|
||||
|
||||
|
||||
@@ -19,35 +19,57 @@ from typing import Optional
|
||||
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.MODEL): DataFunction("get_model"),
|
||||
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", [WebAPICommand("web_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", [WebAPICommand("web_summary", "summary")]
|
||||
),
|
||||
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):
|
||||
|
||||
@@ -17,7 +17,9 @@ 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
|
||||
|
||||
@@ -27,6 +29,70 @@ from pyasic.data.error_codes import MinerErrorData
|
||||
from pyasic.logger import logger
|
||||
|
||||
|
||||
class DataOptions(Enum):
|
||||
MAC = "mac"
|
||||
MODEL = "model"
|
||||
API_VERSION = "api_ver"
|
||||
FW_VERSION = "fw_ver"
|
||||
HOSTNAME = "hostname"
|
||||
HASHRATE = "hashrate"
|
||||
EXPECTED_HASHRATE = "expected_hashrate"
|
||||
HASHBOARDS = "hashboards"
|
||||
ENVIRONMENT_TEMP = "env_temp"
|
||||
WATTAGE = "wattage"
|
||||
WATTAGE_LIMIT = "wattage_limit"
|
||||
FANS = "fans"
|
||||
FAN_PSU = "fan_psu"
|
||||
ERRORS = "errors"
|
||||
FAULT_LIGHT = "fault_light"
|
||||
IS_MINING = "is_mining"
|
||||
UPTIME = "uptime"
|
||||
CONFIG = "config"
|
||||
|
||||
def __str__(self):
|
||||
return self.value
|
||||
|
||||
|
||||
@dataclass
|
||||
class RPCAPICommand:
|
||||
name: str
|
||||
cmd: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class WebAPICommand:
|
||||
name: str
|
||||
cmd: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class GRPCCommand(WebAPICommand):
|
||||
name: str
|
||||
cmd: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class GraphQLCommand(WebAPICommand):
|
||||
name: str
|
||||
cmd: dict
|
||||
|
||||
|
||||
@dataclass
|
||||
class DataFunction:
|
||||
cmd: str
|
||||
kwargs: list[
|
||||
Union[RPCAPICommand, WebAPICommand, GRPCCommand, GraphQLCommand]
|
||||
] = field(default_factory=list)
|
||||
|
||||
|
||||
DataLocations = make_dataclass(
|
||||
"DataLocations",
|
||||
[(enum_value.value, str) for enum_value in DataOptions],
|
||||
)
|
||||
# add default value with
|
||||
# [(enum_value.value, str, , DataFunction(enum_value.value)) for enum_value in DataOptions],
|
||||
|
||||
|
||||
class BaseMiner(ABC):
|
||||
def __init__(self, ip: str, *args, **kwargs) -> None:
|
||||
# interfaces
|
||||
@@ -46,7 +112,7 @@ class BaseMiner(ABC):
|
||||
self.expected_chips = 0
|
||||
self.fan_count = 2
|
||||
# data gathering locations
|
||||
self.data_locations = None
|
||||
self.data_locations: DataLocations = None
|
||||
# autotuning/shutdown support
|
||||
self.supports_autotuning = False
|
||||
self.supports_shutdown = False
|
||||
@@ -359,15 +425,6 @@ class BaseMiner(ABC):
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def get_pools(self, *args, **kwargs) -> List[dict]:
|
||||
"""Get pool information from the miner.
|
||||
|
||||
Returns:
|
||||
Pool groups and quotas in a list of dicts.
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def get_errors(self, *args, **kwargs) -> List[MinerErrorData]:
|
||||
"""Get a list of the errors the miner is experiencing.
|
||||
@@ -414,28 +471,33 @@ class BaseMiner(ABC):
|
||||
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 +527,36 @@ 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"])
|
||||
function = getattr(self, getattr(self.data_locations, data_name).cmd)
|
||||
miner_data[data_name] = await function(**args_to_send)
|
||||
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].
|
||||
|
||||
|
||||
@@ -267,32 +267,6 @@ class CGMinerA10X(CGMiner, A10X):
|
||||
|
||||
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
|
||||
|
||||
@@ -246,32 +246,6 @@ class CGMinerT3HPlus(CGMiner, T3HPlus):
|
||||
|
||||
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
|
||||
|
||||
@@ -113,32 +113,6 @@ class UnknownMiner(BaseMiner):
|
||||
async def get_fw_ver(self) -> Optional[str]:
|
||||
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]:
|
||||
return []
|
||||
|
||||
@@ -155,6 +129,6 @@ class UnknownMiner(BaseMiner):
|
||||
return None
|
||||
|
||||
async def get_data(
|
||||
self, allow_warning: bool = False, data_to_get: list = None
|
||||
self, allow_warning: bool = False, data_to_get: list = None, **kwargs
|
||||
) -> MinerData:
|
||||
return MinerData(ip=str(self.ip))
|
||||
|
||||
@@ -123,9 +123,8 @@ class MinerNetwork:
|
||||
# clear cached miners
|
||||
miner_factory.clear_cached_miners()
|
||||
|
||||
limit = asyncio.Semaphore(settings.get("network_scan_threads", 300))
|
||||
miners = await asyncio.gather(
|
||||
*[self.ping_and_get_miner(host, limit) for host in self.hosts]
|
||||
*[self.ping_and_get_miner(host) for host in self.hosts]
|
||||
)
|
||||
|
||||
# remove all None from the miner list
|
||||
@@ -148,12 +147,8 @@ class MinerNetwork:
|
||||
loop = asyncio.get_event_loop()
|
||||
|
||||
# create a list of scan tasks
|
||||
limit = asyncio.Semaphore(settings.get("network_scan_threads", 300))
|
||||
miners = asyncio.as_completed(
|
||||
[
|
||||
loop.create_task(self.ping_and_get_miner(host, limit))
|
||||
for host in self.hosts
|
||||
]
|
||||
[loop.create_task(self.ping_and_get_miner(host)) for host in self.hosts]
|
||||
)
|
||||
for miner in miners:
|
||||
try:
|
||||
@@ -162,21 +157,16 @@ class MinerNetwork:
|
||||
yield None
|
||||
|
||||
@staticmethod
|
||||
async def ping_and_get_miner(
|
||||
ip: ipaddress.ip_address, semaphore: asyncio.Semaphore
|
||||
) -> Union[None, AnyMiner]:
|
||||
async with semaphore:
|
||||
try:
|
||||
return await ping_and_get_miner(ip)
|
||||
except ConnectionRefusedError:
|
||||
tasks = [
|
||||
ping_and_get_miner(ip, port=port) for port in [4028, 4029, 8889]
|
||||
]
|
||||
for miner in asyncio.as_completed(tasks):
|
||||
try:
|
||||
return await miner
|
||||
except ConnectionRefusedError:
|
||||
pass
|
||||
async def ping_and_get_miner(ip: ipaddress.ip_address) -> Union[None, AnyMiner]:
|
||||
try:
|
||||
return await ping_and_get_miner(ip)
|
||||
except ConnectionRefusedError:
|
||||
tasks = [ping_and_get_miner(ip, port=port) for port in [4028, 4029, 8889]]
|
||||
for miner in asyncio.as_completed(tasks):
|
||||
try:
|
||||
return await miner
|
||||
except ConnectionRefusedError:
|
||||
pass
|
||||
|
||||
|
||||
async def ping_and_get_miner(
|
||||
|
||||
@@ -24,7 +24,6 @@ from httpx import AsyncHTTPTransport
|
||||
_settings = { # defaults
|
||||
"network_ping_retries": 1,
|
||||
"network_ping_timeout": 3,
|
||||
"network_scan_threads": 300,
|
||||
"factory_get_retries": 1,
|
||||
"factory_get_timeout": 3,
|
||||
"get_data_retries": 1,
|
||||
|
||||
@@ -156,6 +156,8 @@ class BOSMinerGQLAPI:
|
||||
) -> dict:
|
||||
url = f"http://{self.ip}/graphql"
|
||||
query = command
|
||||
if command is None:
|
||||
return {}
|
||||
if command.get("query") is None:
|
||||
query = {"query": self.parse_command(command)}
|
||||
try:
|
||||
@@ -189,11 +191,13 @@ class BOSMinerGQLAPI:
|
||||
await client.post(
|
||||
url,
|
||||
json={
|
||||
"query": 'mutation{auth{login(username:"'
|
||||
+ "root"
|
||||
+ '", password:"'
|
||||
+ self.pwd
|
||||
+ '"){__typename}}}'
|
||||
"query": (
|
||||
'mutation{auth{login(username:"'
|
||||
+ "root"
|
||||
+ '", password:"'
|
||||
+ self.pwd
|
||||
+ '"){__typename}}}'
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
@@ -233,7 +237,9 @@ class BOSMinerLuCIAPI:
|
||||
login = {"luci_username": self.username, "luci_password": self.pwd}
|
||||
url = f"http://{self.ip}/cgi-bin/luci"
|
||||
headers = {
|
||||
"User-Agent": "BTC Tools v0.1", # only seems to respond if this user-agent is set
|
||||
"User-Agent": (
|
||||
"BTC Tools v0.1"
|
||||
), # only seems to respond if this user-agent is set
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
}
|
||||
await session.post(url, headers=headers, data=login)
|
||||
|
||||
@@ -2357,17 +2357,21 @@ class ActionsServiceBase(ServiceBase):
|
||||
RebootRequest,
|
||||
RebootResponse,
|
||||
),
|
||||
"/braiins.bos.v1.ActionsService/SetLocateDeviceStatus": grpclib.const.Handler(
|
||||
self.__rpc_set_locate_device_status,
|
||||
grpclib.const.Cardinality.UNARY_UNARY,
|
||||
SetLocateDeviceStatusRequest,
|
||||
LocateDeviceStatusResponse,
|
||||
"/braiins.bos.v1.ActionsService/SetLocateDeviceStatus": (
|
||||
grpclib.const.Handler(
|
||||
self.__rpc_set_locate_device_status,
|
||||
grpclib.const.Cardinality.UNARY_UNARY,
|
||||
SetLocateDeviceStatusRequest,
|
||||
LocateDeviceStatusResponse,
|
||||
)
|
||||
),
|
||||
"/braiins.bos.v1.ActionsService/GetLocateDeviceStatus": grpclib.const.Handler(
|
||||
self.__rpc_get_locate_device_status,
|
||||
grpclib.const.Cardinality.UNARY_UNARY,
|
||||
GetLocateDeviceStatusRequest,
|
||||
LocateDeviceStatusResponse,
|
||||
"/braiins.bos.v1.ActionsService/GetLocateDeviceStatus": (
|
||||
grpclib.const.Handler(
|
||||
self.__rpc_get_locate_device_status,
|
||||
grpclib.const.Cardinality.UNARY_UNARY,
|
||||
GetLocateDeviceStatusRequest,
|
||||
LocateDeviceStatusResponse,
|
||||
)
|
||||
),
|
||||
}
|
||||
|
||||
@@ -2644,17 +2648,21 @@ class PerformanceServiceBase(ServiceBase):
|
||||
GetTunerStateRequest,
|
||||
GetTunerStateResponse,
|
||||
),
|
||||
"/braiins.bos.v1.PerformanceService/ListTargetProfiles": grpclib.const.Handler(
|
||||
self.__rpc_list_target_profiles,
|
||||
grpclib.const.Cardinality.UNARY_UNARY,
|
||||
ListTargetProfilesRequest,
|
||||
ListTargetProfilesResponse,
|
||||
"/braiins.bos.v1.PerformanceService/ListTargetProfiles": (
|
||||
grpclib.const.Handler(
|
||||
self.__rpc_list_target_profiles,
|
||||
grpclib.const.Cardinality.UNARY_UNARY,
|
||||
ListTargetProfilesRequest,
|
||||
ListTargetProfilesResponse,
|
||||
)
|
||||
),
|
||||
"/braiins.bos.v1.PerformanceService/SetDefaultPowerTarget": grpclib.const.Handler(
|
||||
self.__rpc_set_default_power_target,
|
||||
grpclib.const.Cardinality.UNARY_UNARY,
|
||||
SetDefaultPowerTargetRequest,
|
||||
SetPowerTargetResponse,
|
||||
"/braiins.bos.v1.PerformanceService/SetDefaultPowerTarget": (
|
||||
grpclib.const.Handler(
|
||||
self.__rpc_set_default_power_target,
|
||||
grpclib.const.Cardinality.UNARY_UNARY,
|
||||
SetDefaultPowerTargetRequest,
|
||||
SetPowerTargetResponse,
|
||||
)
|
||||
),
|
||||
"/braiins.bos.v1.PerformanceService/SetPowerTarget": grpclib.const.Handler(
|
||||
self.__rpc_set_power_target,
|
||||
@@ -2662,41 +2670,53 @@ class PerformanceServiceBase(ServiceBase):
|
||||
SetPowerTargetRequest,
|
||||
SetPowerTargetResponse,
|
||||
),
|
||||
"/braiins.bos.v1.PerformanceService/IncrementPowerTarget": grpclib.const.Handler(
|
||||
self.__rpc_increment_power_target,
|
||||
grpclib.const.Cardinality.UNARY_UNARY,
|
||||
IncrementPowerTargetRequest,
|
||||
SetPowerTargetResponse,
|
||||
"/braiins.bos.v1.PerformanceService/IncrementPowerTarget": (
|
||||
grpclib.const.Handler(
|
||||
self.__rpc_increment_power_target,
|
||||
grpclib.const.Cardinality.UNARY_UNARY,
|
||||
IncrementPowerTargetRequest,
|
||||
SetPowerTargetResponse,
|
||||
)
|
||||
),
|
||||
"/braiins.bos.v1.PerformanceService/DecrementPowerTarget": grpclib.const.Handler(
|
||||
self.__rpc_decrement_power_target,
|
||||
grpclib.const.Cardinality.UNARY_UNARY,
|
||||
DecrementPowerTargetRequest,
|
||||
SetPowerTargetResponse,
|
||||
"/braiins.bos.v1.PerformanceService/DecrementPowerTarget": (
|
||||
grpclib.const.Handler(
|
||||
self.__rpc_decrement_power_target,
|
||||
grpclib.const.Cardinality.UNARY_UNARY,
|
||||
DecrementPowerTargetRequest,
|
||||
SetPowerTargetResponse,
|
||||
)
|
||||
),
|
||||
"/braiins.bos.v1.PerformanceService/SetDefaultHashrateTarget": grpclib.const.Handler(
|
||||
self.__rpc_set_default_hashrate_target,
|
||||
grpclib.const.Cardinality.UNARY_UNARY,
|
||||
SetDefaultHashrateTargetRequest,
|
||||
SetHashrateTargetResponse,
|
||||
"/braiins.bos.v1.PerformanceService/SetDefaultHashrateTarget": (
|
||||
grpclib.const.Handler(
|
||||
self.__rpc_set_default_hashrate_target,
|
||||
grpclib.const.Cardinality.UNARY_UNARY,
|
||||
SetDefaultHashrateTargetRequest,
|
||||
SetHashrateTargetResponse,
|
||||
)
|
||||
),
|
||||
"/braiins.bos.v1.PerformanceService/SetHashrateTarget": grpclib.const.Handler(
|
||||
self.__rpc_set_hashrate_target,
|
||||
grpclib.const.Cardinality.UNARY_UNARY,
|
||||
SetHashrateTargetRequest,
|
||||
SetHashrateTargetResponse,
|
||||
"/braiins.bos.v1.PerformanceService/SetHashrateTarget": (
|
||||
grpclib.const.Handler(
|
||||
self.__rpc_set_hashrate_target,
|
||||
grpclib.const.Cardinality.UNARY_UNARY,
|
||||
SetHashrateTargetRequest,
|
||||
SetHashrateTargetResponse,
|
||||
)
|
||||
),
|
||||
"/braiins.bos.v1.PerformanceService/IncrementHashrateTarget": grpclib.const.Handler(
|
||||
self.__rpc_increment_hashrate_target,
|
||||
grpclib.const.Cardinality.UNARY_UNARY,
|
||||
IncrementHashrateTargetRequest,
|
||||
SetHashrateTargetResponse,
|
||||
"/braiins.bos.v1.PerformanceService/IncrementHashrateTarget": (
|
||||
grpclib.const.Handler(
|
||||
self.__rpc_increment_hashrate_target,
|
||||
grpclib.const.Cardinality.UNARY_UNARY,
|
||||
IncrementHashrateTargetRequest,
|
||||
SetHashrateTargetResponse,
|
||||
)
|
||||
),
|
||||
"/braiins.bos.v1.PerformanceService/DecrementHashrateTarget": grpclib.const.Handler(
|
||||
self.__rpc_decrement_hashrate_target,
|
||||
grpclib.const.Cardinality.UNARY_UNARY,
|
||||
DecrementHashrateTargetRequest,
|
||||
SetHashrateTargetResponse,
|
||||
"/braiins.bos.v1.PerformanceService/DecrementHashrateTarget": (
|
||||
grpclib.const.Handler(
|
||||
self.__rpc_decrement_hashrate_target,
|
||||
grpclib.const.Cardinality.UNARY_UNARY,
|
||||
DecrementHashrateTargetRequest,
|
||||
SetHashrateTargetResponse,
|
||||
)
|
||||
),
|
||||
"/braiins.bos.v1.PerformanceService/SetDPS": grpclib.const.Handler(
|
||||
self.__rpc_set_dps,
|
||||
@@ -2704,23 +2724,29 @@ class PerformanceServiceBase(ServiceBase):
|
||||
SetDpsRequest,
|
||||
SetDpsResponse,
|
||||
),
|
||||
"/braiins.bos.v1.PerformanceService/SetPerformanceMode": grpclib.const.Handler(
|
||||
self.__rpc_set_performance_mode,
|
||||
grpclib.const.Cardinality.UNARY_UNARY,
|
||||
SetPerformanceModeRequest,
|
||||
PerformanceMode,
|
||||
"/braiins.bos.v1.PerformanceService/SetPerformanceMode": (
|
||||
grpclib.const.Handler(
|
||||
self.__rpc_set_performance_mode,
|
||||
grpclib.const.Cardinality.UNARY_UNARY,
|
||||
SetPerformanceModeRequest,
|
||||
PerformanceMode,
|
||||
)
|
||||
),
|
||||
"/braiins.bos.v1.PerformanceService/GetActivePerformanceMode": grpclib.const.Handler(
|
||||
self.__rpc_get_active_performance_mode,
|
||||
grpclib.const.Cardinality.UNARY_UNARY,
|
||||
GetPerformanceModeRequest,
|
||||
PerformanceMode,
|
||||
"/braiins.bos.v1.PerformanceService/GetActivePerformanceMode": (
|
||||
grpclib.const.Handler(
|
||||
self.__rpc_get_active_performance_mode,
|
||||
grpclib.const.Cardinality.UNARY_UNARY,
|
||||
GetPerformanceModeRequest,
|
||||
PerformanceMode,
|
||||
)
|
||||
),
|
||||
"/braiins.bos.v1.PerformanceService/RemoveTunedProfiles": grpclib.const.Handler(
|
||||
self.__rpc_remove_tuned_profiles,
|
||||
grpclib.const.Cardinality.UNARY_UNARY,
|
||||
RemoveTunedProfilesRequest,
|
||||
RemoveTunedProfilesResponse,
|
||||
"/braiins.bos.v1.PerformanceService/RemoveTunedProfiles": (
|
||||
grpclib.const.Handler(
|
||||
self.__rpc_remove_tuned_profiles,
|
||||
grpclib.const.Cardinality.UNARY_UNARY,
|
||||
RemoveTunedProfilesRequest,
|
||||
RemoveTunedProfilesResponse,
|
||||
)
|
||||
),
|
||||
}
|
||||
|
||||
@@ -2836,17 +2862,21 @@ class ConfigurationServiceBase(ServiceBase):
|
||||
|
||||
def __mapping__(self) -> Dict[str, grpclib.const.Handler]:
|
||||
return {
|
||||
"/braiins.bos.v1.ConfigurationService/GetMinerConfiguration": grpclib.const.Handler(
|
||||
self.__rpc_get_miner_configuration,
|
||||
grpclib.const.Cardinality.UNARY_UNARY,
|
||||
GetMinerConfigurationRequest,
|
||||
GetMinerConfigurationResponse,
|
||||
"/braiins.bos.v1.ConfigurationService/GetMinerConfiguration": (
|
||||
grpclib.const.Handler(
|
||||
self.__rpc_get_miner_configuration,
|
||||
grpclib.const.Cardinality.UNARY_UNARY,
|
||||
GetMinerConfigurationRequest,
|
||||
GetMinerConfigurationResponse,
|
||||
)
|
||||
),
|
||||
"/braiins.bos.v1.ConfigurationService/GetConstraints": grpclib.const.Handler(
|
||||
self.__rpc_get_constraints,
|
||||
grpclib.const.Cardinality.UNARY_UNARY,
|
||||
GetConstraintsRequest,
|
||||
GetConstraintsResponse,
|
||||
"/braiins.bos.v1.ConfigurationService/GetConstraints": (
|
||||
grpclib.const.Handler(
|
||||
self.__rpc_get_constraints,
|
||||
grpclib.const.Cardinality.UNARY_UNARY,
|
||||
GetConstraintsRequest,
|
||||
GetConstraintsResponse,
|
||||
)
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[tool.poetry]
|
||||
name = "pyasic"
|
||||
version = "0.44.2"
|
||||
version = "0.46.0"
|
||||
description = "A simplified and standardized interface for Bitcoin ASICs."
|
||||
authors = ["UpstreamData <brett@upstreamdata.ca>"]
|
||||
repository = "https://github.com/UpstreamData/pyasic"
|
||||
@@ -10,10 +10,10 @@ readme = "README.md"
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.8"
|
||||
httpx = "^0.26.0"
|
||||
asyncssh = "^2.14.1"
|
||||
grpc-requests = "^0.1.12"
|
||||
asyncssh = "^2.14.2"
|
||||
grpc-requests = "^0.1.13"
|
||||
passlib = "^1.7.4"
|
||||
pyaml = "^23.9.7"
|
||||
pyaml = "^23.12.0"
|
||||
toml = "^0.10.2"
|
||||
betterproto = "2.0.0b6"
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ import inspect
|
||||
import sys
|
||||
import unittest
|
||||
import warnings
|
||||
from dataclasses import asdict
|
||||
|
||||
from pyasic.miners.backends import CGMiner # noqa
|
||||
from pyasic.miners.base import BaseMiner
|
||||
@@ -57,7 +58,6 @@ class MinersTest(unittest.TestCase):
|
||||
"mac",
|
||||
"model",
|
||||
"expected_hashrate",
|
||||
"pools",
|
||||
"uptime",
|
||||
"wattage",
|
||||
"wattage_limit",
|
||||
@@ -72,7 +72,9 @@ class MinersTest(unittest.TestCase):
|
||||
miner_api=miner_api,
|
||||
):
|
||||
miner = MINER_CLASSES[miner_model][miner_api]("127.0.0.1")
|
||||
miner_keys = sorted(list(miner.data_locations.keys()))
|
||||
miner_keys = sorted(
|
||||
[str(k) for k in asdict(miner.data_locations).keys()]
|
||||
)
|
||||
self.assertEqual(miner_keys, keys)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user