Update data locations to be typed with dataclasses and enums. (#82)
* feature: swap AntminerModern to new data location style. * bug: fix a bunch of missed instances of `nominal_` naming. * feature: add support for S19 Pro Hydro. * version: bump version number. * dependencies: bump httpx version * version: bump version number. * feature: implement data locations for all remaining miners. * refactor: remove some unused docstrings. * feature: swap AntminerModern to new data location style. * feature: implement data locations for all remaining miners. * refactor: remove some unused docstrings. * bug: fix misnamed data locations, and update base miner get_data to use new data locations. * bug: fix include/exclude implementation on get_data. * bug: swap ePIC to BaseMiner subclass. * feature: add DataOptions to __all__ * tests: update data tests with new data locations method. * bug: remove bad command from bosminer commands. * dependencies: update dependencies. * bug: fix some typing issues with python 3.8, and remove useless semaphore and scan threads. * bug: fix KeyError when pools rpc command returns broken data.
This commit is contained in:
@@ -48,10 +48,10 @@ PrePowerOnMessage = Union[
|
|||||||
|
|
||||||
|
|
||||||
def _crypt(word: str, salt: str) -> str:
|
def _crypt(word: str, salt: str) -> str:
|
||||||
"""Encrypts a word with a salt, using a standard salt format.
|
r"""Encrypts a word with a salt, using a standard salt format.
|
||||||
|
|
||||||
Encrypts a word using a salt with the format
|
Encrypts a word using a salt with the format
|
||||||
'\s*\$(\d+)\$([\w\./]*)\$'. If this format is not used, a
|
\s*\$(\d+)\$([\w\./]*)\$. If this format is not used, a
|
||||||
ValueError is raised.
|
ValueError is raised.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
@@ -62,7 +62,7 @@ def _crypt(word: str, salt: str) -> str:
|
|||||||
An MD5 hash of the word with the salt.
|
An MD5 hash of the word with the salt.
|
||||||
"""
|
"""
|
||||||
# compile a standard format for the salt
|
# compile a standard format for the salt
|
||||||
standard_salt = re.compile("\s*\$(\d+)\$([\w\./]*)\$")
|
standard_salt = re.compile(r"\s*\$(\d+)\$([\w\./]*)\$")
|
||||||
# check if the salt matches
|
# check if the salt matches
|
||||||
match = standard_salt.match(salt)
|
match = standard_salt.match(salt)
|
||||||
# if the matching fails, the salt is incorrect
|
# if the matching fails, the salt is incorrect
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ from pyasic.data import (
|
|||||||
)
|
)
|
||||||
from pyasic.errors import APIError, APIWarning
|
from pyasic.errors import APIError, APIWarning
|
||||||
from pyasic.miners import get_miner
|
from pyasic.miners import get_miner
|
||||||
from pyasic.miners.base import AnyMiner
|
from pyasic.miners.base import AnyMiner, DataOptions
|
||||||
from pyasic.miners.miner_factory import MinerFactory, miner_factory
|
from pyasic.miners.miner_factory import MinerFactory, miner_factory
|
||||||
from pyasic.miners.miner_listener import MinerListener
|
from pyasic.miners.miner_listener import MinerListener
|
||||||
from pyasic.network import MinerNetwork
|
from pyasic.network import MinerNetwork
|
||||||
@@ -50,6 +50,7 @@ __all__ = [
|
|||||||
"APIWarning",
|
"APIWarning",
|
||||||
"get_miner",
|
"get_miner",
|
||||||
"AnyMiner",
|
"AnyMiner",
|
||||||
|
"DataOptions",
|
||||||
"MinerFactory",
|
"MinerFactory",
|
||||||
"miner_factory",
|
"miner_factory",
|
||||||
"MinerListener",
|
"MinerListener",
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
# limitations under the License. -
|
# limitations under the License. -
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from typing import Union
|
from typing import Dict, Union
|
||||||
|
|
||||||
from pyasic.config.base import MinerConfigOption, MinerConfigValue
|
from pyasic.config.base import MinerConfigOption, MinerConfigValue
|
||||||
|
|
||||||
@@ -132,7 +132,7 @@ class MiningModeManual(MinerConfigValue):
|
|||||||
|
|
||||||
global_freq: float
|
global_freq: float
|
||||||
global_volt: float
|
global_volt: float
|
||||||
boards: dict[int, ManualBoardSettings] = field(default_factory=dict)
|
boards: Dict[int, ManualBoardSettings] = field(default_factory=dict)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_dict(cls, dict_conf: Union[dict, None]) -> "MiningModeManual":
|
def from_dict(cls, dict_conf: Union[dict, None]) -> "MiningModeManual":
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
import random
|
import random
|
||||||
import string
|
import string
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from typing import Union
|
from typing import Dict, List, Union
|
||||||
|
|
||||||
from pyasic.config.base import MinerConfigValue
|
from pyasic.config.base import MinerConfigValue
|
||||||
|
|
||||||
@@ -144,7 +144,7 @@ class Pool(MinerConfigValue):
|
|||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class PoolGroup(MinerConfigValue):
|
class PoolGroup(MinerConfigValue):
|
||||||
pools: list[Pool] = field(default_factory=list)
|
pools: List[Pool] = field(default_factory=list)
|
||||||
quota: int = 1
|
quota: int = 1
|
||||||
name: str = None
|
name: str = None
|
||||||
|
|
||||||
@@ -278,7 +278,7 @@ class PoolGroup(MinerConfigValue):
|
|||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class PoolConfig(MinerConfigValue):
|
class PoolConfig(MinerConfigValue):
|
||||||
groups: list[PoolGroup] = field(default_factory=list)
|
groups: List[PoolGroup] = field(default_factory=list)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def default(cls) -> "PoolConfig":
|
def default(cls) -> "PoolConfig":
|
||||||
@@ -292,7 +292,7 @@ class PoolConfig(MinerConfigValue):
|
|||||||
return cls(groups=[PoolGroup.from_dict(g) for g in dict_conf["groups"]])
|
return cls(groups=[PoolGroup.from_dict(g) for g in dict_conf["groups"]])
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def simple(cls, pools: list[Union[Pool, dict[str, str]]]) -> "PoolConfig":
|
def simple(cls, pools: List[Union[Pool, Dict[str, str]]]) -> "PoolConfig":
|
||||||
group_pools = []
|
group_pools = []
|
||||||
for pool in pools:
|
for pool in pools:
|
||||||
if isinstance(pool, dict):
|
if isinstance(pool, dict):
|
||||||
@@ -342,7 +342,10 @@ class PoolConfig(MinerConfigValue):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_api(cls, api_pools: dict) -> "PoolConfig":
|
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"]))
|
pool_data = sorted(pool_data, key=lambda x: int(x["POOL"]))
|
||||||
|
|
||||||
return cls([PoolGroup.from_api(pool_data)])
|
return cls([PoolGroup.from_api(pool_data)])
|
||||||
|
|||||||
@@ -14,7 +14,6 @@
|
|||||||
# limitations under the License. -
|
# limitations under the License. -
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
import asyncio
|
|
||||||
from typing import List, Optional, Union
|
from typing import List, Optional, Union
|
||||||
|
|
||||||
from pyasic.API import APIError
|
from pyasic.API import APIError
|
||||||
@@ -23,50 +22,62 @@ from pyasic.data import Fan, HashBoard
|
|||||||
from pyasic.data.error_codes import MinerErrorData, X19Error
|
from pyasic.data.error_codes import MinerErrorData, X19Error
|
||||||
from pyasic.miners.backends.bmminer import BMMiner
|
from pyasic.miners.backends.bmminer import BMMiner
|
||||||
from pyasic.miners.backends.cgminer import CGMiner
|
from pyasic.miners.backends.cgminer import CGMiner
|
||||||
|
from pyasic.miners.base import (
|
||||||
|
DataFunction,
|
||||||
|
DataLocations,
|
||||||
|
DataOptions,
|
||||||
|
RPCAPICommand,
|
||||||
|
WebAPICommand,
|
||||||
|
)
|
||||||
from pyasic.web.antminer import AntminerModernWebAPI, AntminerOldWebAPI
|
from pyasic.web.antminer import AntminerModernWebAPI, AntminerOldWebAPI
|
||||||
|
|
||||||
ANTMINER_MODERN_DATA_LOC = {
|
ANTMINER_MODERN_DATA_LOC = DataLocations(
|
||||||
"mac": {
|
**{
|
||||||
"cmd": "get_mac",
|
str(DataOptions.MAC): DataFunction(
|
||||||
"kwargs": {"web_get_system_info": {"web": "get_system_info"}},
|
"get_mac", [WebAPICommand("web_get_system_info", "get_system_info")]
|
||||||
},
|
),
|
||||||
"model": {"cmd": "get_model", "kwargs": {}},
|
str(DataOptions.MODEL): DataFunction("get_model"),
|
||||||
"api_ver": {"cmd": "get_api_ver", "kwargs": {"api_version": {"api": "version"}}},
|
str(DataOptions.API_VERSION): DataFunction(
|
||||||
"fw_ver": {"cmd": "get_fw_ver", "kwargs": {"api_version": {"api": "version"}}},
|
"get_api_ver", [RPCAPICommand("api_version", "version")]
|
||||||
"hostname": {
|
),
|
||||||
"cmd": "get_hostname",
|
str(DataOptions.FW_VERSION): DataFunction(
|
||||||
"kwargs": {"web_get_system_info": {"web": "get_system_info"}},
|
"get_fw_ver", [RPCAPICommand("api_version", "version")]
|
||||||
},
|
),
|
||||||
"hashrate": {"cmd": "get_hashrate", "kwargs": {"api_summary": {"api": "summary"}}},
|
str(DataOptions.HOSTNAME): DataFunction(
|
||||||
"expected_hashrate": {
|
"get_hostname", [WebAPICommand("web_get_system_info", "get_system_info")]
|
||||||
"cmd": "get_expected_hashrate",
|
),
|
||||||
"kwargs": {"api_stats": {"api": "stats"}},
|
str(DataOptions.HASHRATE): DataFunction(
|
||||||
},
|
"get_hashrate", [RPCAPICommand("api_summary", "summary")]
|
||||||
"hashboards": {"cmd": "get_hashboards", "kwargs": {"api_stats": {"api": "stats"}}},
|
),
|
||||||
"env_temp": {"cmd": "get_env_temp", "kwargs": {}},
|
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
|
||||||
"wattage": {"cmd": "get_wattage", "kwargs": {}},
|
"get_expected_hashrate", [RPCAPICommand("api_stats", "stats")]
|
||||||
"wattage_limit": {"cmd": "get_wattage_limit", "kwargs": {}},
|
),
|
||||||
"fans": {"cmd": "get_fans", "kwargs": {"api_stats": {"api": "stats"}}},
|
str(DataOptions.HASHBOARDS): DataFunction(
|
||||||
"fan_psu": {"cmd": "get_fan_psu", "kwargs": {}},
|
"get_hashboards", [RPCAPICommand("api_stats", "stats")]
|
||||||
"errors": {"cmd": "get_errors", "kwargs": {"web_summary": {"web": "summary"}}},
|
),
|
||||||
"fault_light": {
|
str(DataOptions.ENVIRONMENT_TEMP): DataFunction("get_env_temp"),
|
||||||
"cmd": "get_fault_light",
|
str(DataOptions.WATTAGE): DataFunction("get_wattage"),
|
||||||
"kwargs": {"web_get_blink_status": {"web": "get_blink_status"}},
|
str(DataOptions.WATTAGE_LIMIT): DataFunction("get_wattage_limit"),
|
||||||
},
|
str(DataOptions.FANS): DataFunction(
|
||||||
"pools": {"cmd": "get_pools", "kwargs": {"api_pools": {"api": "pools"}}},
|
"get_fans", [RPCAPICommand("api_stats", "stats")]
|
||||||
"is_mining": {
|
),
|
||||||
"cmd": "is_mining",
|
str(DataOptions.FAN_PSU): DataFunction("get_fan_psu"),
|
||||||
"kwargs": {"web_get_conf": {"web": "get_miner_conf"}},
|
str(DataOptions.ERRORS): DataFunction(
|
||||||
},
|
"get_errors", [WebAPICommand("web_summary", "summary")]
|
||||||
"uptime": {
|
),
|
||||||
"cmd": "get_uptime",
|
str(DataOptions.FAULT_LIGHT): DataFunction(
|
||||||
"kwargs": {"api_stats": {"api": "stats"}},
|
"get_fault_light",
|
||||||
},
|
[WebAPICommand("web_get_blink_status", "get_blink_status")],
|
||||||
"config": {
|
),
|
||||||
"cmd": "get_config",
|
str(DataOptions.IS_MINING): DataFunction(
|
||||||
"kwargs": {},
|
"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):
|
class AntminerModern(BMMiner):
|
||||||
@@ -298,39 +309,49 @@ class AntminerModern(BMMiner):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
ANTMINER_OLD_DATA_LOC = {
|
ANTMINER_OLD_DATA_LOC = DataLocations(
|
||||||
"mac": {"cmd": "get_mac", "kwargs": {}},
|
**{
|
||||||
"model": {"cmd": "get_model", "kwargs": {}},
|
str(DataOptions.MAC): DataFunction("get_mac"),
|
||||||
"api_ver": {"cmd": "get_api_ver", "kwargs": {"api_version": {"api": "version"}}},
|
str(DataOptions.MODEL): DataFunction("get_model"),
|
||||||
"fw_ver": {"cmd": "get_fw_ver", "kwargs": {"api_version": {"api": "version"}}},
|
str(DataOptions.API_VERSION): DataFunction(
|
||||||
"hostname": {
|
"get_api_ver", [RPCAPICommand("api_version", "version")]
|
||||||
"cmd": "get_hostname",
|
),
|
||||||
"kwargs": {"web_get_system_info": {"web": "get_system_info"}},
|
str(DataOptions.FW_VERSION): DataFunction(
|
||||||
},
|
"get_fw_ver", [RPCAPICommand("api_version", "version")]
|
||||||
"hashrate": {"cmd": "get_hashrate", "kwargs": {"api_summary": {"api": "summary"}}},
|
),
|
||||||
"expected_hashrate": {
|
str(DataOptions.HOSTNAME): DataFunction(
|
||||||
"cmd": "get_expected_hashrate",
|
"get_hostname", [WebAPICommand("web_get_system_info", "get_system_info")]
|
||||||
"kwargs": {"api_stats": {"api": "stats"}},
|
),
|
||||||
},
|
str(DataOptions.HASHRATE): DataFunction(
|
||||||
"hashboards": {"cmd": "get_hashboards", "kwargs": {"api_stats": {"api": "stats"}}},
|
"get_hashrate", [RPCAPICommand("api_summary", "summary")]
|
||||||
"env_temp": {"cmd": "get_env_temp", "kwargs": {}},
|
),
|
||||||
"wattage": {"cmd": "get_wattage", "kwargs": {}},
|
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
|
||||||
"wattage_limit": {"cmd": "get_wattage_limit", "kwargs": {}},
|
"get_expected_hashrate", [RPCAPICommand("api_stats", "stats")]
|
||||||
"fans": {"cmd": "get_fans", "kwargs": {"api_stats": {"api": "stats"}}},
|
),
|
||||||
"fan_psu": {"cmd": "get_fan_psu", "kwargs": {}},
|
str(DataOptions.HASHBOARDS): DataFunction(
|
||||||
"errors": {"cmd": "get_errors", "kwargs": {}},
|
"get_hashboards", [RPCAPICommand("api_stats", "stats")]
|
||||||
"fault_light": {
|
),
|
||||||
"cmd": "get_fault_light",
|
str(DataOptions.ENVIRONMENT_TEMP): DataFunction("get_env_temp"),
|
||||||
"kwargs": {"web_get_blink_status": {"web": "get_blink_status"}},
|
str(DataOptions.WATTAGE): DataFunction("get_wattage"),
|
||||||
},
|
str(DataOptions.WATTAGE_LIMIT): DataFunction("get_wattage_limit"),
|
||||||
"pools": {"cmd": "get_pools", "kwargs": {"api_pools": {"api": "pools"}}},
|
str(DataOptions.FANS): DataFunction(
|
||||||
"is_mining": {
|
"get_fans", [RPCAPICommand("api_stats", "stats")]
|
||||||
"cmd": "is_mining",
|
),
|
||||||
"kwargs": {"web_get_conf": {"web": "get_miner_conf"}},
|
str(DataOptions.FAN_PSU): DataFunction("get_fan_psu"),
|
||||||
},
|
str(DataOptions.ERRORS): DataFunction("get_errors"),
|
||||||
"uptime": {"cmd": "get_uptime", "kwargs": {"api_stats": {"api": "stats"}}},
|
str(DataOptions.FAULT_LIGHT): DataFunction(
|
||||||
"config": {"cmd": "get_config", "kwargs": {}},
|
"get_fault_light",
|
||||||
}
|
[WebAPICommand("web_get_blink_status", "get_blink_status")],
|
||||||
|
),
|
||||||
|
str(DataOptions.IS_MINING): DataFunction(
|
||||||
|
"is_mining", [WebAPICommand("web_get_conf", "get_miner_conf")]
|
||||||
|
),
|
||||||
|
str(DataOptions.UPTIME): DataFunction(
|
||||||
|
"get_uptime", [RPCAPICommand("api_stats", "stats")]
|
||||||
|
),
|
||||||
|
str(DataOptions.CONFIG): DataFunction("get_config"),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class AntminerOld(CGMiner):
|
class AntminerOld(CGMiner):
|
||||||
|
|||||||
@@ -22,32 +22,48 @@ from pyasic.config import MinerConfig
|
|||||||
from pyasic.data import Fan, HashBoard
|
from pyasic.data import Fan, HashBoard
|
||||||
from pyasic.data.error_codes import MinerErrorData
|
from pyasic.data.error_codes import MinerErrorData
|
||||||
from pyasic.errors import APIError
|
from pyasic.errors import APIError
|
||||||
from pyasic.miners.base import BaseMiner
|
from pyasic.miners.base import (
|
||||||
|
BaseMiner,
|
||||||
|
DataFunction,
|
||||||
|
DataLocations,
|
||||||
|
DataOptions,
|
||||||
|
RPCAPICommand,
|
||||||
|
)
|
||||||
|
|
||||||
BFGMINER_DATA_LOC = {
|
BFGMINER_DATA_LOC = DataLocations(
|
||||||
"mac": {"cmd": "get_mac", "kwargs": {}},
|
**{
|
||||||
"model": {"cmd": "get_model", "kwargs": {}},
|
str(DataOptions.MAC): DataFunction("get_mac"),
|
||||||
"api_ver": {"cmd": "get_api_ver", "kwargs": {"api_version": {"api": "version"}}},
|
str(DataOptions.MODEL): DataFunction("get_model"),
|
||||||
"fw_ver": {"cmd": "get_fw_ver", "kwargs": {"api_version": {"api": "version"}}},
|
str(DataOptions.API_VERSION): DataFunction(
|
||||||
"hostname": {"cmd": "get_hostname", "kwargs": {}},
|
"get_api_ver", [RPCAPICommand("api_version", "version")]
|
||||||
"hashrate": {"cmd": "get_hashrate", "kwargs": {"api_summary": {"api": "summary"}}},
|
),
|
||||||
"expected_hashrate": {
|
str(DataOptions.FW_VERSION): DataFunction(
|
||||||
"cmd": "get_expected_hashrate",
|
"get_fw_ver", [RPCAPICommand("api_version", "version")]
|
||||||
"kwargs": {"api_stats": {"api": "stats"}},
|
),
|
||||||
},
|
str(DataOptions.HOSTNAME): DataFunction("get_hostname"),
|
||||||
"hashboards": {"cmd": "get_hashboards", "kwargs": {"api_stats": {"api": "stats"}}},
|
str(DataOptions.HASHRATE): DataFunction(
|
||||||
"env_temp": {"cmd": "get_env_temp", "kwargs": {}},
|
"get_hashrate", [RPCAPICommand("api_summary", "summary")]
|
||||||
"wattage": {"cmd": "get_wattage", "kwargs": {}},
|
),
|
||||||
"wattage_limit": {"cmd": "get_wattage_limit", "kwargs": {}},
|
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
|
||||||
"fans": {"cmd": "get_fans", "kwargs": {"api_stats": {"api": "stats"}}},
|
"get_expected_hashrate", [RPCAPICommand("api_stats", "stats")]
|
||||||
"fan_psu": {"cmd": "get_fan_psu", "kwargs": {}},
|
),
|
||||||
"errors": {"cmd": "get_errors", "kwargs": {}},
|
str(DataOptions.HASHBOARDS): DataFunction(
|
||||||
"fault_light": {"cmd": "get_fault_light", "kwargs": {}},
|
"get_hashboards", [RPCAPICommand("api_stats", "stats")]
|
||||||
"pools": {"cmd": "get_pools", "kwargs": {"api_pools": {"api": "pools"}}},
|
),
|
||||||
"is_mining": {"cmd": "is_mining", "kwargs": {}},
|
str(DataOptions.ENVIRONMENT_TEMP): DataFunction("get_env_temp"),
|
||||||
"uptime": {"cmd": "get_uptime", "kwargs": {}},
|
str(DataOptions.WATTAGE): DataFunction("get_wattage"),
|
||||||
"config": {"cmd": "get_config", "kwargs": {}},
|
str(DataOptions.WATTAGE_LIMIT): DataFunction("get_wattage_limit"),
|
||||||
}
|
str(DataOptions.FANS): DataFunction(
|
||||||
|
"get_fans", [RPCAPICommand("api_stats", "stats")]
|
||||||
|
),
|
||||||
|
str(DataOptions.FAN_PSU): DataFunction("get_fan_psu"),
|
||||||
|
str(DataOptions.ERRORS): DataFunction("get_errors"),
|
||||||
|
str(DataOptions.FAULT_LIGHT): DataFunction("get_fault_light"),
|
||||||
|
str(DataOptions.IS_MINING): DataFunction("is_mining"),
|
||||||
|
str(DataOptions.UPTIME): DataFunction("get_uptime"),
|
||||||
|
str(DataOptions.CONFIG): DataFunction("get_config"),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class BFGMiner(BaseMiner):
|
class BFGMiner(BaseMiner):
|
||||||
@@ -268,32 +284,6 @@ class BFGMiner(BaseMiner):
|
|||||||
|
|
||||||
return fans
|
return fans
|
||||||
|
|
||||||
async def get_pools(self, api_pools: dict = None) -> List[dict]:
|
|
||||||
groups = []
|
|
||||||
|
|
||||||
if not api_pools:
|
|
||||||
try:
|
|
||||||
api_pools = await self.api.pools()
|
|
||||||
except APIError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if api_pools:
|
|
||||||
try:
|
|
||||||
pools = {}
|
|
||||||
for i, pool in enumerate(api_pools["POOLS"]):
|
|
||||||
pools[f"pool_{i + 1}_url"] = (
|
|
||||||
pool["URL"]
|
|
||||||
.replace("stratum+tcp://", "")
|
|
||||||
.replace("stratum2+tcp://", "")
|
|
||||||
)
|
|
||||||
pools[f"pool_{i + 1}_user"] = pool["User"]
|
|
||||||
pools["quota"] = pool["Quota"] if pool.get("Quota") else "0"
|
|
||||||
|
|
||||||
groups.append(pools)
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
return groups
|
|
||||||
|
|
||||||
async def get_errors(self) -> List[MinerErrorData]:
|
async def get_errors(self) -> List[MinerErrorData]:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|||||||
@@ -20,41 +20,55 @@ from pyasic.data import HashBoard
|
|||||||
from pyasic.errors import APIError
|
from pyasic.errors import APIError
|
||||||
from pyasic.logger import logger
|
from pyasic.logger import logger
|
||||||
from pyasic.miners.backends import BFGMiner
|
from pyasic.miners.backends import BFGMiner
|
||||||
|
from pyasic.miners.base import (
|
||||||
|
DataFunction,
|
||||||
|
DataLocations,
|
||||||
|
DataOptions,
|
||||||
|
RPCAPICommand,
|
||||||
|
WebAPICommand,
|
||||||
|
)
|
||||||
from pyasic.web.goldshell import GoldshellWebAPI
|
from pyasic.web.goldshell import GoldshellWebAPI
|
||||||
|
|
||||||
GOLDSHELL_DATA_LOC = {
|
GOLDSHELL_DATA_LOC = DataLocations(
|
||||||
"mac": {"cmd": "get_mac", "kwargs": {"web_setting": {"web": "setting"}}},
|
**{
|
||||||
"model": {"cmd": "get_model", "kwargs": {}},
|
str(DataOptions.MAC): DataFunction(
|
||||||
"api_ver": {"cmd": "get_api_ver", "kwargs": {"api_version": {"api": "version"}}},
|
"get_mac", [WebAPICommand("web_setting", "setting")]
|
||||||
"fw_ver": {"cmd": "get_fw_ver", "kwargs": {"web_status": {"web": "status"}}},
|
),
|
||||||
"hostname": {"cmd": "get_hostname", "kwargs": {}},
|
str(DataOptions.MODEL): DataFunction("get_model"),
|
||||||
"hashrate": {"cmd": "get_hashrate", "kwargs": {"api_summary": {"api": "summary"}}},
|
str(DataOptions.API_VERSION): DataFunction(
|
||||||
"expected_hashrate": {
|
"get_api_ver", [RPCAPICommand("api_version", "version")]
|
||||||
"cmd": "get_expected_hashrate",
|
),
|
||||||
"kwargs": {"api_stats": {"api": "stats"}},
|
str(DataOptions.FW_VERSION): DataFunction(
|
||||||
},
|
"get_fw_ver", [WebAPICommand("web_status", "status")]
|
||||||
"hashboards": {
|
),
|
||||||
"cmd": "get_hashboards",
|
str(DataOptions.HOSTNAME): DataFunction("get_hostname"),
|
||||||
"kwargs": {
|
str(DataOptions.HASHRATE): DataFunction(
|
||||||
"api_devs": {"api": "devs"},
|
"get_hashrate", [RPCAPICommand("api_summary", "summary")]
|
||||||
"api_devdetails": {"api": "devdetails"},
|
),
|
||||||
},
|
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
|
||||||
},
|
"get_expected_hashrate", [RPCAPICommand("api_stats", "stats")]
|
||||||
"env_temp": {"cmd": "get_env_temp", "kwargs": {}},
|
),
|
||||||
"wattage": {"cmd": "get_wattage", "kwargs": {}},
|
str(DataOptions.HASHBOARDS): DataFunction(
|
||||||
"wattage_limit": {"cmd": "get_wattage_limit", "kwargs": {}},
|
"get_hashboards",
|
||||||
"fans": {"cmd": "get_fans", "kwargs": {"api_stats": {"api": "stats"}}},
|
[
|
||||||
"fan_psu": {"cmd": "get_fan_psu", "kwargs": {}},
|
RPCAPICommand("api_devs", "devs"),
|
||||||
"errors": {"cmd": "get_errors", "kwargs": {}},
|
RPCAPICommand("api_devdetails", "devdetails"),
|
||||||
"fault_light": {"cmd": "get_fault_light", "kwargs": {}},
|
],
|
||||||
"pools": {"cmd": "get_pools", "kwargs": {"api_pools": {"api": "pools"}}},
|
),
|
||||||
"is_mining": {"cmd": "is_mining", "kwargs": {}},
|
str(DataOptions.ENVIRONMENT_TEMP): DataFunction("get_env_temp"),
|
||||||
"uptime": {"cmd": "get_uptime", "kwargs": {}},
|
str(DataOptions.WATTAGE): DataFunction("get_wattage"),
|
||||||
"config": {
|
str(DataOptions.WATTAGE_LIMIT): DataFunction("get_wattage_limit"),
|
||||||
"cmd": "get_config",
|
str(DataOptions.FANS): DataFunction(
|
||||||
"kwargs": {},
|
"get_fans", [RPCAPICommand("api_stats", "stats")]
|
||||||
},
|
),
|
||||||
}
|
str(DataOptions.FAN_PSU): DataFunction("get_fan_psu"),
|
||||||
|
str(DataOptions.ERRORS): DataFunction("get_errors"),
|
||||||
|
str(DataOptions.FAULT_LIGHT): DataFunction("get_fault_light"),
|
||||||
|
str(DataOptions.IS_MINING): DataFunction("is_mining"),
|
||||||
|
str(DataOptions.UPTIME): DataFunction("get_uptime"),
|
||||||
|
str(DataOptions.CONFIG): DataFunction("get_config"),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class BFGMinerGoldshell(BFGMiner):
|
class BFGMinerGoldshell(BFGMiner):
|
||||||
|
|||||||
@@ -23,32 +23,50 @@ from pyasic.config import MinerConfig
|
|||||||
from pyasic.data import Fan, HashBoard
|
from pyasic.data import Fan, HashBoard
|
||||||
from pyasic.data.error_codes import MinerErrorData
|
from pyasic.data.error_codes import MinerErrorData
|
||||||
from pyasic.errors import APIError
|
from pyasic.errors import APIError
|
||||||
from pyasic.miners.base import BaseMiner
|
from pyasic.miners.base import (
|
||||||
|
BaseMiner,
|
||||||
|
DataFunction,
|
||||||
|
DataLocations,
|
||||||
|
DataOptions,
|
||||||
|
RPCAPICommand,
|
||||||
|
)
|
||||||
|
|
||||||
BMMINER_DATA_LOC = {
|
BMMINER_DATA_LOC = DataLocations(
|
||||||
"mac": {"cmd": "get_mac", "kwargs": {}},
|
**{
|
||||||
"model": {"cmd": "get_model", "kwargs": {}},
|
str(DataOptions.MAC): DataFunction("get_mac"),
|
||||||
"api_ver": {"cmd": "get_api_ver", "kwargs": {"api_version": {"api": "version"}}},
|
str(DataOptions.MODEL): DataFunction("get_model"),
|
||||||
"fw_ver": {"cmd": "get_fw_ver", "kwargs": {"api_version": {"api": "version"}}},
|
str(DataOptions.API_VERSION): DataFunction(
|
||||||
"hostname": {"cmd": "get_hostname", "kwargs": {}},
|
"get_api_ver", [RPCAPICommand("api_version", "version")]
|
||||||
"hashrate": {"cmd": "get_hashrate", "kwargs": {"api_summary": {"api": "summary"}}},
|
),
|
||||||
"expected_hashrate": {
|
str(DataOptions.FW_VERSION): DataFunction(
|
||||||
"cmd": "get_expected_hashrate",
|
"get_fw_ver", [RPCAPICommand("api_version", "version")]
|
||||||
"kwargs": {"api_stats": {"api": "stats"}},
|
),
|
||||||
},
|
str(DataOptions.HOSTNAME): DataFunction("get_hostname"),
|
||||||
"hashboards": {"cmd": "get_hashboards", "kwargs": {"api_stats": {"api": "stats"}}},
|
str(DataOptions.HASHRATE): DataFunction(
|
||||||
"env_temp": {"cmd": "get_env_temp", "kwargs": {}},
|
"get_hashrate", [RPCAPICommand("api_summary", "summary")]
|
||||||
"wattage": {"cmd": "get_wattage", "kwargs": {}},
|
),
|
||||||
"wattage_limit": {"cmd": "get_wattage_limit", "kwargs": {}},
|
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
|
||||||
"fans": {"cmd": "get_fans", "kwargs": {"api_stats": {"api": "stats"}}},
|
"get_expected_hashrate", [RPCAPICommand("api_stats", "stats")]
|
||||||
"fan_psu": {"cmd": "get_fan_psu", "kwargs": {}},
|
),
|
||||||
"errors": {"cmd": "get_errors", "kwargs": {}},
|
str(DataOptions.HASHBOARDS): DataFunction(
|
||||||
"fault_light": {"cmd": "get_fault_light", "kwargs": {}},
|
"get_hashboards", [RPCAPICommand("api_stats", "stats")]
|
||||||
"pools": {"cmd": "get_pools", "kwargs": {"api_pools": {"api": "pools"}}},
|
),
|
||||||
"is_mining": {"cmd": "is_mining", "kwargs": {}},
|
str(DataOptions.ENVIRONMENT_TEMP): DataFunction("get_env_temp"),
|
||||||
"uptime": {"cmd": "get_uptime", "kwargs": {"api_stats": {"api": "stats"}}},
|
str(DataOptions.WATTAGE): DataFunction("get_wattage"),
|
||||||
"config": {"cmd": "get_config", "kwargs": {}},
|
str(DataOptions.WATTAGE_LIMIT): DataFunction("get_wattage_limit"),
|
||||||
}
|
str(DataOptions.FANS): DataFunction(
|
||||||
|
"get_fans", [RPCAPICommand("api_stats", "stats")]
|
||||||
|
),
|
||||||
|
str(DataOptions.FAN_PSU): DataFunction("get_fan_psu"),
|
||||||
|
str(DataOptions.ERRORS): DataFunction("get_errors"),
|
||||||
|
str(DataOptions.FAULT_LIGHT): DataFunction("get_fault_light"),
|
||||||
|
str(DataOptions.IS_MINING): DataFunction("is_mining"),
|
||||||
|
str(DataOptions.UPTIME): DataFunction(
|
||||||
|
"get_uptime", [RPCAPICommand("api_stats", "stats")]
|
||||||
|
),
|
||||||
|
str(DataOptions.CONFIG): DataFunction("get_config"),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class BMMiner(BaseMiner):
|
class BMMiner(BaseMiner):
|
||||||
@@ -315,32 +333,6 @@ class BMMiner(BaseMiner):
|
|||||||
|
|
||||||
return fans
|
return fans
|
||||||
|
|
||||||
async def get_pools(self, api_pools: dict = None) -> List[dict]:
|
|
||||||
groups = []
|
|
||||||
|
|
||||||
if not api_pools:
|
|
||||||
try:
|
|
||||||
api_pools = await self.api.pools()
|
|
||||||
except APIError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if api_pools:
|
|
||||||
try:
|
|
||||||
pools = {}
|
|
||||||
for i, pool in enumerate(api_pools["POOLS"]):
|
|
||||||
pools[f"pool_{i + 1}_url"] = (
|
|
||||||
pool["URL"]
|
|
||||||
.replace("stratum+tcp://", "")
|
|
||||||
.replace("stratum2+tcp://", "")
|
|
||||||
)
|
|
||||||
pools[f"pool_{i + 1}_user"] = pool["User"]
|
|
||||||
pools["quota"] = pool["Quota"] if pool.get("Quota") else "0"
|
|
||||||
|
|
||||||
groups.append(pools)
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
return groups
|
|
||||||
|
|
||||||
async def get_errors(self) -> List[MinerErrorData]:
|
async def get_errors(self) -> List[MinerErrorData]:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|||||||
@@ -27,157 +27,157 @@ from pyasic.config.mining import MiningModePowerTune
|
|||||||
from pyasic.data import Fan, HashBoard
|
from pyasic.data import Fan, HashBoard
|
||||||
from pyasic.data.error_codes import BraiinsOSError, MinerErrorData
|
from pyasic.data.error_codes import BraiinsOSError, MinerErrorData
|
||||||
from pyasic.errors import APIError
|
from pyasic.errors import APIError
|
||||||
from pyasic.miners.base import BaseMiner
|
from pyasic.miners.base import (
|
||||||
|
BaseMiner,
|
||||||
|
DataFunction,
|
||||||
|
DataLocations,
|
||||||
|
DataOptions,
|
||||||
|
GraphQLCommand,
|
||||||
|
RPCAPICommand,
|
||||||
|
WebAPICommand,
|
||||||
|
)
|
||||||
from pyasic.web.bosminer import BOSMinerWebAPI
|
from pyasic.web.bosminer import BOSMinerWebAPI
|
||||||
|
|
||||||
BOSMINER_DATA_LOC = {
|
BOSMINER_DATA_LOC = DataLocations(
|
||||||
"mac": {
|
**{
|
||||||
"cmd": "get_mac",
|
str(DataOptions.MAC): DataFunction(
|
||||||
"kwargs": {
|
"get_mac",
|
||||||
"web_net_conf": {"web": "/cgi-bin/luci/admin/network/iface_status/lan"}
|
[
|
||||||
},
|
WebAPICommand(
|
||||||
},
|
"web_net_conf", "/cgi-bin/luci/admin/network/iface_status/lan"
|
||||||
"model": {"cmd": "get_model", "kwargs": {}},
|
)
|
||||||
"api_ver": {"cmd": "get_api_ver", "kwargs": {"api_version": {"api": "version"}}},
|
],
|
||||||
"fw_ver": {
|
),
|
||||||
"cmd": "get_fw_ver",
|
str(DataOptions.MODEL): DataFunction("get_model"),
|
||||||
"kwargs": {
|
str(DataOptions.API_VERSION): DataFunction(
|
||||||
"graphql_version": {"web": {"bos": {"info": {"version": {"full": None}}}}}
|
"get_api_ver", [RPCAPICommand("api_version", "version")]
|
||||||
},
|
),
|
||||||
},
|
str(DataOptions.FW_VERSION): DataFunction(
|
||||||
"hostname": {
|
"get_fw_ver",
|
||||||
"cmd": "get_hostname",
|
[
|
||||||
"kwargs": {"graphql_hostname": {"web": {"bos": {"hostname": None}}}},
|
GraphQLCommand(
|
||||||
},
|
"graphql_version", {"bos": {"info": {"version": {"full": None}}}}
|
||||||
"hashrate": {
|
)
|
||||||
"cmd": "get_hashrate",
|
],
|
||||||
"kwargs": {
|
),
|
||||||
"api_summary": {"api": "summary"},
|
str(DataOptions.HOSTNAME): DataFunction(
|
||||||
"graphql_hashrate": {
|
"get_hostname",
|
||||||
"web": {
|
[GraphQLCommand("graphql_hostname", {"bos": {"hostname": None}})],
|
||||||
"bosminer": {
|
),
|
||||||
"info": {"workSolver": {"realHashrate": {"mhs1M": None}}}
|
str(DataOptions.HASHRATE): DataFunction(
|
||||||
}
|
"get_hashrate",
|
||||||
},
|
[
|
||||||
},
|
RPCAPICommand("api_summary", "summary"),
|
||||||
},
|
GraphQLCommand(
|
||||||
},
|
"graphql_hashrate",
|
||||||
"expected_hashrate": {
|
{
|
||||||
"cmd": "get_expected_hashrate",
|
"bosminer": {
|
||||||
"kwargs": {"api_devs": {"api": "devs"}},
|
"info": {"workSolver": {"realHashrate": {"mhs1M": None}}}
|
||||||
},
|
}
|
||||||
"hashboards": {
|
},
|
||||||
"cmd": "get_hashboards",
|
),
|
||||||
"kwargs": {
|
],
|
||||||
"api_temps": {"api": "temps"},
|
),
|
||||||
"api_devdetails": {"api": "devdetails"},
|
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
|
||||||
"api_devs": {"api": "devs"},
|
"get_expected_hashrate", [RPCAPICommand("api_devs", "devs")]
|
||||||
"graphql_boards": {
|
),
|
||||||
"web": {
|
str(DataOptions.HASHBOARDS): DataFunction(
|
||||||
"bosminer": {
|
"get_hashboards",
|
||||||
"info": {
|
[
|
||||||
"workSolver": {
|
RPCAPICommand("api_temps", "temps"),
|
||||||
"childSolvers": {
|
RPCAPICommand("api_devdetails", "devdetails"),
|
||||||
"name": None,
|
RPCAPICommand("api_devs", "devs"),
|
||||||
"realHashrate": {"mhs1M": None},
|
GraphQLCommand(
|
||||||
"hwDetails": {"chips": None},
|
"graphql_boards",
|
||||||
"temperatures": {"degreesC": None},
|
{
|
||||||
|
"bosminer": {
|
||||||
|
"info": {
|
||||||
|
"workSolver": {
|
||||||
|
"childSolvers": {
|
||||||
|
"name": None,
|
||||||
|
"realHashrate": {"mhs1M": None},
|
||||||
|
"hwDetails": {"chips": None},
|
||||||
|
"temperatures": {"degreesC": None},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
},
|
),
|
||||||
},
|
],
|
||||||
},
|
),
|
||||||
},
|
str(DataOptions.ENVIRONMENT_TEMP): DataFunction("get_env_temp"),
|
||||||
"wattage": {
|
str(DataOptions.WATTAGE): DataFunction(
|
||||||
"cmd": "get_wattage",
|
"get_wattage",
|
||||||
"kwargs": {
|
[
|
||||||
"api_tunerstatus": {"api": "tunerstatus"},
|
RPCAPICommand("api_tunerstatus", "tunerstatus"),
|
||||||
"graphql_wattage": {
|
GraphQLCommand(
|
||||||
"web": {
|
"graphql_wattage",
|
||||||
"bosminer": {
|
{
|
||||||
"info": {"workSolver": {"power": {"approxConsumptionW": None}}}
|
"bosminer": {
|
||||||
}
|
"info": {
|
||||||
}
|
"workSolver": {"power": {"approxConsumptionW": None}}
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
"wattage_limit": {
|
),
|
||||||
"cmd": "get_wattage_limit",
|
],
|
||||||
"kwargs": {
|
),
|
||||||
"api_tunerstatus": {"api": "tunerstatus"},
|
str(DataOptions.WATTAGE_LIMIT): DataFunction(
|
||||||
"graphql_wattage_limit": {
|
"get_wattage_limit",
|
||||||
"web": {
|
[
|
||||||
"bosminer": {"info": {"workSolver": {"power": {"limitW": None}}}}
|
RPCAPICommand("api_tunerstatus", "tunerstatus"),
|
||||||
}
|
GraphQLCommand(
|
||||||
},
|
"graphql_wattage_limit",
|
||||||
},
|
{"bosminer": {"info": {"workSolver": {"power": {"limitW": None}}}}},
|
||||||
},
|
),
|
||||||
"fans": {
|
],
|
||||||
"cmd": "get_fans",
|
),
|
||||||
"kwargs": {
|
str(DataOptions.FANS): DataFunction(
|
||||||
"api_fans": {"api": "fans"},
|
"get_fans",
|
||||||
"graphql_fans": {
|
[
|
||||||
"web": {"bosminer": {"info": {"fans": {"name": None, "rpm": None}}}}
|
RPCAPICommand("api_fans", "fans"),
|
||||||
},
|
GraphQLCommand(
|
||||||
},
|
"graphql_fans",
|
||||||
},
|
{"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",
|
str(DataOptions.FAN_PSU): DataFunction("get_fan_psu"),
|
||||||
"kwargs": {
|
str(DataOptions.ERRORS): DataFunction(
|
||||||
"api_tunerstatus": {"api": "tunerstatus"},
|
"get_errors",
|
||||||
"graphql_errors": {
|
[
|
||||||
"web": {
|
RPCAPICommand("api_tunerstatus", "tunerstatus"),
|
||||||
"bosminer": {
|
GraphQLCommand(
|
||||||
"info": {
|
"graphql_errors",
|
||||||
"workSolver": {
|
{
|
||||||
"childSolvers": {
|
"bosminer": {
|
||||||
"name": None,
|
"info": {
|
||||||
"tuner": {"statusMessages": None},
|
"workSolver": {
|
||||||
|
"childSolvers": {
|
||||||
|
"name": None,
|
||||||
|
"tuner": {"statusMessages": None},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
),
|
||||||
},
|
],
|
||||||
},
|
),
|
||||||
},
|
str(DataOptions.FAULT_LIGHT): DataFunction(
|
||||||
"fault_light": {
|
"get_fault_light",
|
||||||
"cmd": "get_fault_light",
|
[GraphQLCommand("graphql_fault_light", {"bos": {"faultLight": None}})],
|
||||||
"kwargs": {"graphql_fault_light": {"web": {"bos": {"faultLight": None}}}},
|
),
|
||||||
},
|
str(DataOptions.IS_MINING): DataFunction(
|
||||||
"pools": {
|
"is_mining", [RPCAPICommand("api_devdetails", "devdetails")]
|
||||||
"cmd": "get_pools",
|
),
|
||||||
"kwargs": {
|
str(DataOptions.UPTIME): DataFunction(
|
||||||
"api_pools": {"api": "pools"},
|
"get_uptime", [RPCAPICommand("api_summary", "summary")]
|
||||||
"graphql_pools": {
|
),
|
||||||
"web": {
|
str(DataOptions.CONFIG): DataFunction("get_config"),
|
||||||
"bosminer": {
|
}
|
||||||
"config": {
|
)
|
||||||
"... on BosminerConfig": {
|
|
||||||
"groups": {
|
|
||||||
"pools": {"url": None, "user": None},
|
|
||||||
"strategy": {
|
|
||||||
"... on QuotaStrategy": {"quota": None}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"is_mining": {
|
|
||||||
"cmd": "is_mining",
|
|
||||||
"kwargs": {"api_devdetails": {"api": "devdetails"}},
|
|
||||||
},
|
|
||||||
"uptime": {"cmd": "get_uptime", "kwargs": {"api_summary": {"api": "summary"}}},
|
|
||||||
"config": {"cmd": "get_config", "kwargs": {}},
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class BOSMiner(BaseMiner):
|
class BOSMiner(BaseMiner):
|
||||||
@@ -231,7 +231,6 @@ class BOSMiner(BaseMiner):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
async def fault_light_on(self) -> bool:
|
async def fault_light_on(self) -> bool:
|
||||||
"""Sends command to turn on fault light on the miner."""
|
|
||||||
logging.debug(f"{self}: Sending fault_light on command.")
|
logging.debug(f"{self}: Sending fault_light on command.")
|
||||||
ret = await self.send_ssh_command("miner fault_light on")
|
ret = await self.send_ssh_command("miner fault_light on")
|
||||||
logging.debug(f"{self}: fault_light on command completed.")
|
logging.debug(f"{self}: fault_light on command completed.")
|
||||||
@@ -241,7 +240,6 @@ class BOSMiner(BaseMiner):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
async def fault_light_off(self) -> bool:
|
async def fault_light_off(self) -> bool:
|
||||||
"""Sends command to turn off fault light on the miner."""
|
|
||||||
logging.debug(f"{self}: Sending fault_light off command.")
|
logging.debug(f"{self}: Sending fault_light off command.")
|
||||||
self.light = False
|
self.light = False
|
||||||
ret = await self.send_ssh_command("miner fault_light off")
|
ret = await self.send_ssh_command("miner fault_light off")
|
||||||
@@ -252,11 +250,9 @@ class BOSMiner(BaseMiner):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
async def restart_backend(self) -> bool:
|
async def restart_backend(self) -> bool:
|
||||||
"""Restart bosminer hashing process. Wraps [`restart_bosminer`][pyasic.miners.backends.bosminer.BOSMiner.restart_bosminer] to standardize."""
|
|
||||||
return await self.restart_bosminer()
|
return await self.restart_bosminer()
|
||||||
|
|
||||||
async def restart_bosminer(self) -> bool:
|
async def restart_bosminer(self) -> bool:
|
||||||
"""Restart bosminer hashing process."""
|
|
||||||
logging.debug(f"{self}: Sending bosminer restart command.")
|
logging.debug(f"{self}: Sending bosminer restart command.")
|
||||||
ret = await self.send_ssh_command("/etc/init.d/bosminer restart")
|
ret = await self.send_ssh_command("/etc/init.d/bosminer restart")
|
||||||
logging.debug(f"{self}: bosminer restart command completed.")
|
logging.debug(f"{self}: bosminer restart command completed.")
|
||||||
@@ -285,7 +281,6 @@ class BOSMiner(BaseMiner):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
async def reboot(self) -> bool:
|
async def reboot(self) -> bool:
|
||||||
"""Reboots power to the physical miner."""
|
|
||||||
logging.debug(f"{self}: Sending reboot command.")
|
logging.debug(f"{self}: Sending reboot command.")
|
||||||
ret = await self.send_ssh_command("/sbin/reboot")
|
ret = await self.send_ssh_command("/sbin/reboot")
|
||||||
logging.debug(f"{self}: Reboot command completed.")
|
logging.debug(f"{self}: Reboot command completed.")
|
||||||
@@ -833,95 +828,6 @@ class BOSMiner(BaseMiner):
|
|||||||
async def get_fan_psu(self) -> Optional[int]:
|
async def get_fan_psu(self) -> Optional[int]:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
async def get_pools(
|
|
||||||
self, api_pools: dict = None, graphql_pools: dict = None
|
|
||||||
) -> List[dict]:
|
|
||||||
if not graphql_pools and not api_pools:
|
|
||||||
try:
|
|
||||||
graphql_pools = await self.web.send_command(
|
|
||||||
{
|
|
||||||
"bosminer": {
|
|
||||||
"config": {
|
|
||||||
"... on BosminerConfig": {
|
|
||||||
"groups": {
|
|
||||||
"pools": {"urluser"},
|
|
||||||
"strategy": {"... on QuotaStrategy": {"quota"}},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
except APIError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if graphql_pools:
|
|
||||||
groups = []
|
|
||||||
try:
|
|
||||||
g = graphql_pools["data"]["bosminer"]["config"]["groups"]
|
|
||||||
for group in g:
|
|
||||||
pools = {"quota": group["strategy"]["quota"]}
|
|
||||||
for i, pool in enumerate(group["pools"]):
|
|
||||||
pools[f"pool_{i + 1}_url"] = (
|
|
||||||
pool["url"]
|
|
||||||
.replace("stratum+tcp://", "")
|
|
||||||
.replace("stratum2+tcp://", "")
|
|
||||||
)
|
|
||||||
pools[f"pool_{i + 1}_user"] = pool["user"]
|
|
||||||
groups.append(pools)
|
|
||||||
return groups
|
|
||||||
except (KeyError, TypeError):
|
|
||||||
pass
|
|
||||||
|
|
||||||
if not api_pools:
|
|
||||||
try:
|
|
||||||
api_pools = await self.api.pools()
|
|
||||||
except APIError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if api_pools:
|
|
||||||
seen = []
|
|
||||||
groups = [{"quota": "0"}]
|
|
||||||
if api_pools.get("POOLS"):
|
|
||||||
for i, pool in enumerate(api_pools["POOLS"]):
|
|
||||||
if len(seen) == 0:
|
|
||||||
seen.append(pool["User"])
|
|
||||||
if not pool["User"] in seen:
|
|
||||||
# need to use get_config, as this will never read perfectly as there are some bad edge cases
|
|
||||||
groups = []
|
|
||||||
cfg = await self.get_config()
|
|
||||||
if cfg:
|
|
||||||
for group in cfg.pool_groups:
|
|
||||||
pools = {"quota": group.quota}
|
|
||||||
for _i, _pool in enumerate(group.pools):
|
|
||||||
pools[f"pool_{_i + 1}_url"] = _pool.url.replace(
|
|
||||||
"stratum+tcp://", ""
|
|
||||||
).replace("stratum2+tcp://", "")
|
|
||||||
pools[f"pool_{_i + 1}_user"] = _pool.username
|
|
||||||
groups.append(pools)
|
|
||||||
return groups
|
|
||||||
else:
|
|
||||||
groups[0][f"pool_{i + 1}_url"] = (
|
|
||||||
pool["URL"]
|
|
||||||
.replace("stratum+tcp://", "")
|
|
||||||
.replace("stratum2+tcp://", "")
|
|
||||||
)
|
|
||||||
groups[0][f"pool_{i + 1}_user"] = pool["User"]
|
|
||||||
else:
|
|
||||||
groups = []
|
|
||||||
cfg = await self.get_config()
|
|
||||||
if cfg:
|
|
||||||
for group in cfg.pool_groups:
|
|
||||||
pools = {"quota": group.quota}
|
|
||||||
for _i, _pool in enumerate(group.pools):
|
|
||||||
pools[f"pool_{_i + 1}_url"] = _pool.url.replace(
|
|
||||||
"stratum+tcp://", ""
|
|
||||||
).replace("stratum2+tcp://", "")
|
|
||||||
pools[f"pool_{_i + 1}_user"] = _pool.username
|
|
||||||
groups.append(pools)
|
|
||||||
return groups
|
|
||||||
return groups
|
|
||||||
|
|
||||||
async def get_errors(
|
async def get_errors(
|
||||||
self, api_tunerstatus: dict = None, graphql_errors: dict = None
|
self, api_tunerstatus: dict = None, graphql_errors: dict = None
|
||||||
) -> List[MinerErrorData]:
|
) -> List[MinerErrorData]:
|
||||||
|
|||||||
@@ -136,9 +136,6 @@ class BOSMinerOld(BOSMiner):
|
|||||||
async def get_fw_ver(self, *args, **kwargs) -> Optional[str]:
|
async def get_fw_ver(self, *args, **kwargs) -> Optional[str]:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
async def get_pools(self, *args, **kwargs) -> List[dict]:
|
|
||||||
return []
|
|
||||||
|
|
||||||
async def get_errors(self, *args, **kwargs) -> List[MinerErrorData]:
|
async def get_errors(self, *args, **kwargs) -> List[MinerErrorData]:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|||||||
@@ -23,74 +23,86 @@ from pyasic.config import MinerConfig, MiningModeConfig
|
|||||||
from pyasic.data import Fan, HashBoard
|
from pyasic.data import Fan, HashBoard
|
||||||
from pyasic.data.error_codes import MinerErrorData, WhatsminerError
|
from pyasic.data.error_codes import MinerErrorData, WhatsminerError
|
||||||
from pyasic.errors import APIError
|
from pyasic.errors import APIError
|
||||||
from pyasic.miners.base import BaseMiner
|
from pyasic.miners.base import (
|
||||||
|
BaseMiner,
|
||||||
|
DataFunction,
|
||||||
|
DataLocations,
|
||||||
|
DataOptions,
|
||||||
|
RPCAPICommand,
|
||||||
|
WebAPICommand,
|
||||||
|
)
|
||||||
|
|
||||||
BTMINER_DATA_LOC = {
|
BTMINER_DATA_LOC = DataLocations(
|
||||||
"mac": {
|
**{
|
||||||
"cmd": "get_mac",
|
str(DataOptions.MAC): DataFunction(
|
||||||
"kwargs": {
|
"get_mac",
|
||||||
"api_summary": {"api": "summary"},
|
[
|
||||||
"api_get_miner_info": {"api": "get_miner_info"},
|
RPCAPICommand("api_summary", "summary"),
|
||||||
},
|
RPCAPICommand("api_get_miner_info", "get_miner_info"),
|
||||||
},
|
],
|
||||||
"model": {"cmd": "get_model", "kwargs": {}},
|
),
|
||||||
"api_ver": {
|
str(DataOptions.MODEL): DataFunction("get_model"),
|
||||||
"cmd": "get_api_ver",
|
str(DataOptions.API_VERSION): DataFunction(
|
||||||
"kwargs": {"api_get_version": {"api": "get_version"}},
|
"get_api_ver", [RPCAPICommand("api_get_version", "get_version")]
|
||||||
},
|
),
|
||||||
"fw_ver": {
|
str(DataOptions.FW_VERSION): DataFunction(
|
||||||
"cmd": "get_fw_ver",
|
"get_fw_ver",
|
||||||
"kwargs": {
|
[
|
||||||
"api_get_version": {"api": "get_version"},
|
RPCAPICommand("api_get_version", "get_version"),
|
||||||
"api_summary": {"api": "summary"},
|
RPCAPICommand("api_summary", "summary"),
|
||||||
},
|
],
|
||||||
},
|
),
|
||||||
"hostname": {
|
str(DataOptions.HOSTNAME): DataFunction(
|
||||||
"cmd": "get_hostname",
|
"get_hostname", [RPCAPICommand("api_get_miner_info", "get_miner_info")]
|
||||||
"kwargs": {"api_get_miner_info": {"api": "get_miner_info"}},
|
),
|
||||||
},
|
str(DataOptions.HASHRATE): DataFunction(
|
||||||
"hashrate": {"cmd": "get_hashrate", "kwargs": {"api_summary": {"api": "summary"}}},
|
"get_hashrate", [RPCAPICommand("api_summary", "summary")]
|
||||||
"expected_hashrate": {
|
),
|
||||||
"cmd": "get_expected_hashrate",
|
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
|
||||||
"kwargs": {"api_summary": {"api": "summary"}},
|
"get_expected_hashrate", [RPCAPICommand("api_summary", "summary")]
|
||||||
},
|
),
|
||||||
"hashboards": {"cmd": "get_hashboards", "kwargs": {"api_devs": {"api": "devs"}}},
|
str(DataOptions.HASHBOARDS): DataFunction(
|
||||||
"env_temp": {"cmd": "get_env_temp", "kwargs": {"api_summary": {"api": "summary"}}},
|
"get_hashboards", [RPCAPICommand("api_devs", "devs")]
|
||||||
"wattage": {"cmd": "get_wattage", "kwargs": {"api_summary": {"api": "summary"}}},
|
),
|
||||||
"wattage_limit": {
|
str(DataOptions.ENVIRONMENT_TEMP): DataFunction(
|
||||||
"cmd": "get_wattage_limit",
|
"get_env_temp", [RPCAPICommand("api_summary", "summary")]
|
||||||
"kwargs": {"api_summary": {"api": "summary"}},
|
),
|
||||||
},
|
str(DataOptions.WATTAGE): DataFunction(
|
||||||
"fans": {
|
"get_wattage", [RPCAPICommand("api_summary", "summary")]
|
||||||
"cmd": "get_fans",
|
),
|
||||||
"kwargs": {
|
str(DataOptions.WATTAGE_LIMIT): DataFunction(
|
||||||
"api_summary": {"api": "summary"},
|
"get_wattage_limit", [RPCAPICommand("api_summary", "summary")]
|
||||||
"api_get_psu": {"api": "get_psu"},
|
),
|
||||||
},
|
str(DataOptions.FANS): DataFunction(
|
||||||
},
|
"get_fans",
|
||||||
"fan_psu": {
|
[
|
||||||
"cmd": "get_fan_psu",
|
RPCAPICommand("api_summary", "summary"),
|
||||||
"kwargs": {
|
RPCAPICommand("api_get_psu", "get_psu"),
|
||||||
"api_summary": {"api": "summary"},
|
],
|
||||||
"api_get_psu": {"api": "get_psu"},
|
),
|
||||||
},
|
str(DataOptions.FAN_PSU): DataFunction(
|
||||||
},
|
"get_fan_psu",
|
||||||
"errors": {
|
[
|
||||||
"cmd": "get_errors",
|
RPCAPICommand("api_summary", "summary"),
|
||||||
"kwargs": {
|
RPCAPICommand("api_get_psu", "get_psu"),
|
||||||
"api_summary": {"api": "summary"},
|
],
|
||||||
"api_get_error_code": {"api": "get_error_code"},
|
),
|
||||||
},
|
str(DataOptions.ERRORS): DataFunction(
|
||||||
},
|
"get_errors", [RPCAPICommand("api_get_error_code", "get_error_code")]
|
||||||
"fault_light": {
|
),
|
||||||
"cmd": "get_fault_light",
|
str(DataOptions.FAULT_LIGHT): DataFunction(
|
||||||
"kwargs": {"api_get_miner_info": {"api": "get_miner_info"}},
|
"get_fault_light",
|
||||||
},
|
[RPCAPICommand("api_get_miner_info", "get_miner_info")],
|
||||||
"pools": {"cmd": "get_pools", "kwargs": {"api_pools": {"api": "pools"}}},
|
),
|
||||||
"is_mining": {"cmd": "is_mining", "kwargs": {"api_status": {"api": "status"}}},
|
str(DataOptions.IS_MINING): DataFunction(
|
||||||
"uptime": {"cmd": "get_uptime", "kwargs": {"api_summary": {"api": "summary"}}},
|
"is_mining", [RPCAPICommand("api_status", "status")]
|
||||||
"config": {"cmd": "get_config", "kwargs": {}},
|
),
|
||||||
}
|
str(DataOptions.UPTIME): DataFunction(
|
||||||
|
"get_uptime", [RPCAPICommand("api_summary", "summary")]
|
||||||
|
),
|
||||||
|
str(DataOptions.CONFIG): DataFunction("get_config"),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class BTMiner(BaseMiner):
|
class BTMiner(BaseMiner):
|
||||||
@@ -529,32 +541,6 @@ class BTMiner(BaseMiner):
|
|||||||
except (KeyError, TypeError):
|
except (KeyError, TypeError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
async def get_pools(self, api_pools: dict = None) -> List[dict]:
|
|
||||||
groups = []
|
|
||||||
|
|
||||||
if not api_pools:
|
|
||||||
try:
|
|
||||||
api_pools = await self.api.pools()
|
|
||||||
except APIError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if api_pools:
|
|
||||||
try:
|
|
||||||
pools = {}
|
|
||||||
for i, pool in enumerate(api_pools["POOLS"]):
|
|
||||||
pools[f"pool_{i + 1}_url"] = (
|
|
||||||
pool["URL"]
|
|
||||||
.replace("stratum+tcp://", "")
|
|
||||||
.replace("stratum2+tcp://", "")
|
|
||||||
)
|
|
||||||
pools[f"pool_{i + 1}_user"] = pool["User"]
|
|
||||||
pools["quota"] = pool["Quota"] if pool.get("Quota") else "0"
|
|
||||||
|
|
||||||
groups.append(pools)
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
return groups
|
|
||||||
|
|
||||||
async def get_errors(
|
async def get_errors(
|
||||||
self, api_summary: dict = None, api_get_error_code: dict = None
|
self, api_summary: dict = None, api_get_error_code: dict = None
|
||||||
) -> List[MinerErrorData]:
|
) -> List[MinerErrorData]:
|
||||||
|
|||||||
@@ -23,32 +23,50 @@ from pyasic.config import MinerConfig
|
|||||||
from pyasic.data import Fan, HashBoard
|
from pyasic.data import Fan, HashBoard
|
||||||
from pyasic.data.error_codes import MinerErrorData
|
from pyasic.data.error_codes import MinerErrorData
|
||||||
from pyasic.errors import APIError
|
from pyasic.errors import APIError
|
||||||
from pyasic.miners.base import BaseMiner
|
from pyasic.miners.base import (
|
||||||
|
BaseMiner,
|
||||||
|
DataFunction,
|
||||||
|
DataLocations,
|
||||||
|
DataOptions,
|
||||||
|
RPCAPICommand,
|
||||||
|
)
|
||||||
|
|
||||||
CGMINER_DATA_LOC = {
|
CGMINER_DATA_LOC = DataLocations(
|
||||||
"mac": {"cmd": "get_mac", "kwargs": {}},
|
**{
|
||||||
"model": {"cmd": "get_model", "kwargs": {}},
|
str(DataOptions.MAC): DataFunction("get_mac"),
|
||||||
"api_ver": {"cmd": "get_api_ver", "kwargs": {"api_version": {"api": "version"}}},
|
str(DataOptions.MODEL): DataFunction("get_model"),
|
||||||
"fw_ver": {"cmd": "get_fw_ver", "kwargs": {"api_version": {"api": "version"}}},
|
str(DataOptions.API_VERSION): DataFunction(
|
||||||
"hostname": {"cmd": "get_hostname", "kwargs": {}},
|
"get_api_ver", [RPCAPICommand("api_version", "version")]
|
||||||
"hashrate": {"cmd": "get_hashrate", "kwargs": {"api_summary": {"api": "summary"}}},
|
),
|
||||||
"expected_hashrate": {
|
str(DataOptions.FW_VERSION): DataFunction(
|
||||||
"cmd": "get_expected_hashrate",
|
"get_fw_ver", [RPCAPICommand("api_version", "version")]
|
||||||
"kwargs": {"api_stats": {"api": "stats"}},
|
),
|
||||||
},
|
str(DataOptions.HOSTNAME): DataFunction("get_hostname"),
|
||||||
"hashboards": {"cmd": "get_hashboards", "kwargs": {"api_stats": {"api": "stats"}}},
|
str(DataOptions.HASHRATE): DataFunction(
|
||||||
"env_temp": {"cmd": "get_env_temp", "kwargs": {}},
|
"get_hashrate", [RPCAPICommand("api_summary", "summary")]
|
||||||
"wattage": {"cmd": "get_wattage", "kwargs": {}},
|
),
|
||||||
"wattage_limit": {"cmd": "get_wattage_limit", "kwargs": {}},
|
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
|
||||||
"fans": {"cmd": "get_fans", "kwargs": {"api_stats": {"api": "stats"}}},
|
"get_expected_hashrate", [RPCAPICommand("api_stats", "stats")]
|
||||||
"fan_psu": {"cmd": "get_fan_psu", "kwargs": {}},
|
),
|
||||||
"errors": {"cmd": "get_errors", "kwargs": {}},
|
str(DataOptions.HASHBOARDS): DataFunction(
|
||||||
"fault_light": {"cmd": "get_fault_light", "kwargs": {}},
|
"get_hashboards", [RPCAPICommand("api_stats", "stats")]
|
||||||
"pools": {"cmd": "get_pools", "kwargs": {"api_pools": {"api": "pools"}}},
|
),
|
||||||
"is_mining": {"cmd": "is_mining", "kwargs": {}},
|
str(DataOptions.ENVIRONMENT_TEMP): DataFunction("get_env_temp"),
|
||||||
"uptime": {"cmd": "get_uptime", "kwargs": {"api_stats": {"api": "stats"}}},
|
str(DataOptions.WATTAGE): DataFunction("get_wattage"),
|
||||||
"config": {"cmd": "get_config", "kwargs": {}},
|
str(DataOptions.WATTAGE_LIMIT): DataFunction("get_wattage_limit"),
|
||||||
}
|
str(DataOptions.FANS): DataFunction(
|
||||||
|
"get_fans", [RPCAPICommand("api_stats", "stats")]
|
||||||
|
),
|
||||||
|
str(DataOptions.FAN_PSU): DataFunction("get_fan_psu"),
|
||||||
|
str(DataOptions.ERRORS): DataFunction("get_errors"),
|
||||||
|
str(DataOptions.FAULT_LIGHT): DataFunction("get_fault_light"),
|
||||||
|
str(DataOptions.IS_MINING): DataFunction("is_mining"),
|
||||||
|
str(DataOptions.UPTIME): DataFunction(
|
||||||
|
"get_uptime", [RPCAPICommand("api_stats", "stats")]
|
||||||
|
),
|
||||||
|
str(DataOptions.CONFIG): DataFunction("get_config"),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class CGMiner(BaseMiner):
|
class CGMiner(BaseMiner):
|
||||||
@@ -94,11 +112,9 @@ class CGMiner(BaseMiner):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
async def restart_backend(self) -> bool:
|
async def restart_backend(self) -> bool:
|
||||||
"""Restart cgminer hashing process. Wraps [`restart_cgminer`][pyasic.miners.backends.cgminer.CGMiner.restart_cgminer] to standardize."""
|
|
||||||
return await self.restart_cgminer()
|
return await self.restart_cgminer()
|
||||||
|
|
||||||
async def restart_cgminer(self) -> bool:
|
async def restart_cgminer(self) -> bool:
|
||||||
"""Restart cgminer hashing process."""
|
|
||||||
commands = ["cgminer-api restart", "/usr/bin/cgminer-monitor >/dev/null 2>&1"]
|
commands = ["cgminer-api restart", "/usr/bin/cgminer-monitor >/dev/null 2>&1"]
|
||||||
commands = ";".join(commands)
|
commands = ";".join(commands)
|
||||||
ret = await self.send_ssh_command(commands)
|
ret = await self.send_ssh_command(commands)
|
||||||
@@ -107,7 +123,6 @@ class CGMiner(BaseMiner):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
async def reboot(self) -> bool:
|
async def reboot(self) -> bool:
|
||||||
"""Reboots power to the physical miner."""
|
|
||||||
logging.debug(f"{self}: Sending reboot command.")
|
logging.debug(f"{self}: Sending reboot command.")
|
||||||
ret = await self.send_ssh_command("reboot")
|
ret = await self.send_ssh_command("reboot")
|
||||||
if ret is None:
|
if ret is None:
|
||||||
@@ -328,32 +343,6 @@ class CGMiner(BaseMiner):
|
|||||||
async def get_fan_psu(self) -> Optional[int]:
|
async def get_fan_psu(self) -> Optional[int]:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
async def get_pools(self, api_pools: dict = None) -> List[dict]:
|
|
||||||
groups = []
|
|
||||||
|
|
||||||
if not api_pools:
|
|
||||||
try:
|
|
||||||
api_pools = await self.api.pools()
|
|
||||||
except APIError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if api_pools:
|
|
||||||
try:
|
|
||||||
pools = {}
|
|
||||||
for i, pool in enumerate(api_pools["POOLS"]):
|
|
||||||
pools[f"pool_{i + 1}_url"] = (
|
|
||||||
pool["URL"]
|
|
||||||
.replace("stratum+tcp://", "")
|
|
||||||
.replace("stratum2+tcp://", "")
|
|
||||||
)
|
|
||||||
pools[f"pool_{i + 1}_user"] = pool["User"]
|
|
||||||
pools["quota"] = pool["Quota"] if pool.get("Quota") else "0"
|
|
||||||
|
|
||||||
groups.append(pools)
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
return groups
|
|
||||||
|
|
||||||
async def get_errors(self) -> List[MinerErrorData]:
|
async def get_errors(self) -> List[MinerErrorData]:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|||||||
@@ -23,37 +23,52 @@ from pyasic.data import Fan, HashBoard
|
|||||||
from pyasic.data.error_codes import MinerErrorData
|
from pyasic.data.error_codes import MinerErrorData
|
||||||
from pyasic.errors import APIError
|
from pyasic.errors import APIError
|
||||||
from pyasic.miners.backends import CGMiner
|
from pyasic.miners.backends import CGMiner
|
||||||
|
from pyasic.miners.base import DataFunction, DataLocations, DataOptions, RPCAPICommand
|
||||||
|
|
||||||
AVALON_DATA_LOC = {
|
AVALON_DATA_LOC = DataLocations(
|
||||||
"mac": {"cmd": "get_mac", "kwargs": {"api_version": {"api": "version"}}},
|
**{
|
||||||
"model": {"cmd": "get_model", "kwargs": {}},
|
str(DataOptions.MAC): DataFunction(
|
||||||
"api_ver": {"cmd": "get_api_ver", "kwargs": {"api_version": {"api": "version"}}},
|
"get_mac", [RPCAPICommand("api_version", "version")]
|
||||||
"fw_ver": {"cmd": "get_fw_ver", "kwargs": {"api_version": {"api": "version"}}},
|
),
|
||||||
"hostname": {"cmd": "get_hostname", "kwargs": {"mac": {"api": "version"}}},
|
str(DataOptions.MODEL): DataFunction("get_model"),
|
||||||
"hashrate": {"cmd": "get_hashrate", "kwargs": {"api_devs": {"api": "devs"}}},
|
str(DataOptions.API_VERSION): DataFunction(
|
||||||
"expected_hashrate": {
|
"get_api_ver", [RPCAPICommand("api_version", "version")]
|
||||||
"cmd": "get_expected_hashrate",
|
),
|
||||||
"kwargs": {"api_stats": {"api": "stats"}},
|
str(DataOptions.FW_VERSION): DataFunction(
|
||||||
},
|
"get_fw_ver", [RPCAPICommand("api_version", "version")]
|
||||||
"hashboards": {"cmd": "get_hashboards", "kwargs": {"api_stats": {"api": "stats"}}},
|
),
|
||||||
"env_temp": {"cmd": "get_env_temp", "kwargs": {"api_stats": {"api": "stats"}}},
|
str(DataOptions.HOSTNAME): DataFunction(
|
||||||
"wattage": {"cmd": "get_wattage", "kwargs": {}},
|
"get_hostname", [RPCAPICommand("api_version", "version")]
|
||||||
"wattage_limit": {
|
),
|
||||||
"cmd": "get_wattage_limit",
|
str(DataOptions.HASHRATE): DataFunction(
|
||||||
"kwargs": {"api_stats": {"api": "stats"}},
|
"get_hashrate", [RPCAPICommand("api_devs", "devs")]
|
||||||
},
|
),
|
||||||
"fans": {"cmd": "get_fans", "kwargs": {"api_stats": {"api": "stats"}}},
|
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
|
||||||
"fan_psu": {"cmd": "get_fan_psu", "kwargs": {}},
|
"get_expected_hashrate", [RPCAPICommand("api_stats", "stats")]
|
||||||
"errors": {"cmd": "get_errors", "kwargs": {}},
|
),
|
||||||
"fault_light": {
|
str(DataOptions.HASHBOARDS): DataFunction(
|
||||||
"cmd": "get_fault_light",
|
"get_hashboards", [RPCAPICommand("api_stats", "stats")]
|
||||||
"kwargs": {"api_stats": {"api": "stats"}},
|
),
|
||||||
},
|
str(DataOptions.ENVIRONMENT_TEMP): DataFunction(
|
||||||
"pools": {"cmd": "get_pools", "kwargs": {"api_pools": {"api": "pools"}}},
|
"get_env_temp", [RPCAPICommand("api_stats", "stats")]
|
||||||
"is_mining": {"cmd": "is_mining", "kwargs": {}},
|
),
|
||||||
"uptime": {"cmd": "get_uptime", "kwargs": {}},
|
str(DataOptions.WATTAGE): DataFunction("get_wattage"),
|
||||||
"config": {"cmd": "get_config", "kwargs": {}},
|
str(DataOptions.WATTAGE_LIMIT): DataFunction(
|
||||||
}
|
"get_wattage_limit", [RPCAPICommand("api_stats", "stats")]
|
||||||
|
),
|
||||||
|
str(DataOptions.FANS): DataFunction(
|
||||||
|
"get_fans", [RPCAPICommand("api_stats", "stats")]
|
||||||
|
),
|
||||||
|
str(DataOptions.FAN_PSU): DataFunction("get_fan_psu"),
|
||||||
|
str(DataOptions.ERRORS): DataFunction("get_errors"),
|
||||||
|
str(DataOptions.FAULT_LIGHT): DataFunction(
|
||||||
|
"get_fault_light", [RPCAPICommand("api_stats", "stats")]
|
||||||
|
),
|
||||||
|
str(DataOptions.IS_MINING): DataFunction("is_mining"),
|
||||||
|
str(DataOptions.UPTIME): DataFunction("get_uptime"),
|
||||||
|
str(DataOptions.CONFIG): DataFunction("get_config"),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class CGMinerAvalon(CGMiner):
|
class CGMinerAvalon(CGMiner):
|
||||||
@@ -116,7 +131,7 @@ class CGMinerAvalon(CGMiner):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def parse_stats(stats):
|
def parse_stats(stats):
|
||||||
_stats_items = re.findall(".+?\[*?]", stats)
|
_stats_items = re.findall(".+?\\[*?]", stats)
|
||||||
stats_items = []
|
stats_items = []
|
||||||
stats_dict = {}
|
stats_dict = {}
|
||||||
for item in _stats_items:
|
for item in _stats_items:
|
||||||
@@ -318,32 +333,6 @@ class CGMinerAvalon(CGMiner):
|
|||||||
pass
|
pass
|
||||||
return fans_data
|
return fans_data
|
||||||
|
|
||||||
async def get_pools(self, api_pools: dict = None) -> List[dict]:
|
|
||||||
groups = []
|
|
||||||
|
|
||||||
if not api_pools:
|
|
||||||
try:
|
|
||||||
api_pools = await self.api.pools()
|
|
||||||
except APIError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if api_pools:
|
|
||||||
try:
|
|
||||||
pools = {}
|
|
||||||
for i, pool in enumerate(api_pools["POOLS"]):
|
|
||||||
pools[f"pool_{i + 1}_url"] = (
|
|
||||||
pool["URL"]
|
|
||||||
.replace("stratum+tcp://", "")
|
|
||||||
.replace("stratum2+tcp://", "")
|
|
||||||
)
|
|
||||||
pools[f"pool_{i + 1}_user"] = pool["User"]
|
|
||||||
pools["quota"] = pool["Quota"] if pool.get("Quota") else "0"
|
|
||||||
|
|
||||||
groups.append(pools)
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
return groups
|
|
||||||
|
|
||||||
async def get_errors(self) -> List[MinerErrorData]:
|
async def get_errors(self) -> List[MinerErrorData]:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|||||||
@@ -14,52 +14,74 @@
|
|||||||
# limitations under the License. -
|
# limitations under the License. -
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from typing import List, Optional, Tuple, Union
|
from typing import List, Optional, Tuple
|
||||||
|
|
||||||
|
from pyasic import MinerConfig
|
||||||
from pyasic.data import Fan, HashBoard
|
from pyasic.data import Fan, HashBoard
|
||||||
from pyasic.data.error_codes import MinerErrorData, X19Error
|
from pyasic.data.error_codes import MinerErrorData, X19Error
|
||||||
from pyasic.config import MinerConfig, MiningModeConfig
|
from pyasic.config import MinerConfig, MiningModeConfig
|
||||||
from pyasic.errors import APIError
|
from pyasic.errors import APIError
|
||||||
from pyasic.logger import logger
|
from pyasic.logger import logger
|
||||||
from pyasic.miners.backends.bmminer import BMMiner
|
from pyasic.miners.base import (
|
||||||
|
BaseMiner,
|
||||||
|
DataFunction,
|
||||||
|
DataLocations,
|
||||||
|
DataOptions,
|
||||||
|
WebAPICommand,
|
||||||
|
)
|
||||||
from pyasic.web.epic import ePICWebAPI
|
from pyasic.web.epic import ePICWebAPI
|
||||||
|
|
||||||
EPIC_DATA_LOC = {
|
EPIC_DATA_LOC = DataLocations(
|
||||||
"mac": {"cmd": "get_mac", "kwargs": {"web_summary": {"web": "network"}}},
|
**{
|
||||||
"model": {"cmd": "get_model", "kwargs": {}},
|
str(DataOptions.MAC): DataFunction(
|
||||||
"api_ver": {"cmd": "get_api_ver", "kwargs": {"api_version": {"api": "version"}}},
|
"get_mac", [WebAPICommand("web_network", "network")]
|
||||||
"fw_ver": {"cmd": "get_fw_ver", "kwargs": {"web_summary": {"web": "summary"}}},
|
),
|
||||||
"hostname": {"cmd": "get_hostname", "kwargs": {"web_summary": {"web": "summary"}}},
|
str(DataOptions.MODEL): DataFunction("get_model"),
|
||||||
"hashrate": {"cmd": "get_hashrate", "kwargs": {"web_summary": {"web": "summary"}}},
|
str(DataOptions.API_VERSION): DataFunction("get_api_ver"),
|
||||||
"expected_hashrate": {
|
str(DataOptions.FW_VERSION): DataFunction(
|
||||||
"cmd": "get_expected_hashrate",
|
"get_fw_ver", [WebAPICommand("web_summary", "summary")]
|
||||||
"kwargs": {"web_summary": {"web": "summary"}},
|
),
|
||||||
},
|
str(DataOptions.HOSTNAME): DataFunction(
|
||||||
"hashboards": {
|
"get_hostname", [WebAPICommand("web_summary", "summary")]
|
||||||
"cmd": "get_hashboards",
|
),
|
||||||
"kwargs": {
|
str(DataOptions.HASHRATE): DataFunction(
|
||||||
"web_summary": {"web": "summary"},
|
"get_hashrate", [WebAPICommand("web_summary", "summary")]
|
||||||
"web_hashrate": {"web": "hashrate"},
|
),
|
||||||
},
|
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
|
||||||
},
|
"get_expected_hashrate", [WebAPICommand("web_summary", "summary")]
|
||||||
"env_temp": {"cmd": "get_env_temp", "kwargs": {}},
|
),
|
||||||
"wattage": {"cmd": "get_wattage", "kwargs": {"web_summary": {"web": "summary"}}},
|
str(DataOptions.HASHBOARDS): DataFunction(
|
||||||
"wattage_limit": {"cmd": "get_wattage_limit", "kwargs": {}},
|
"get_hashboards",
|
||||||
"fans": {"cmd": "get_fans", "kwargs": {"web_summary": {"web": "summary"}}},
|
[
|
||||||
"fan_psu": {"cmd": "get_fan_psu", "kwargs": {}},
|
WebAPICommand("web_summary", "summary"),
|
||||||
"fault_light": {
|
WebAPICommand("web_hashrate", "hashrate"),
|
||||||
"cmd": "get_fault_light",
|
],
|
||||||
"kwargs": {"web_summary": {"web": "summary"}},
|
),
|
||||||
},
|
str(DataOptions.ENVIRONMENT_TEMP): DataFunction("get_env_temp"),
|
||||||
"pools": {"cmd": "get_pools", "kwargs": {"web_summary": {"web": "summary"}}},
|
str(DataOptions.WATTAGE): DataFunction(
|
||||||
"is_mining": {"cmd": "is_mining", "kwargs": {}},
|
"get_wattage", [WebAPICommand("web_summary", "summary")]
|
||||||
"uptime": {"cmd": "get_uptime", "kwargs": {"web_summary": {"web": "summary"}}},
|
),
|
||||||
"errors": {"cmd": "get_errors", "kwargs": {"web_summary": {"web": "summary"}}},
|
str(DataOptions.WATTAGE_LIMIT): DataFunction("get_wattage_limit"),
|
||||||
"config": {"cmd": "get_config", "kwargs": {}},
|
str(DataOptions.FANS): DataFunction(
|
||||||
}
|
"get_fans", [WebAPICommand("web_summary", "summary")]
|
||||||
|
),
|
||||||
|
str(DataOptions.FAN_PSU): DataFunction("get_fan_psu"),
|
||||||
|
str(DataOptions.ERRORS): DataFunction(
|
||||||
|
"get_errors", [WebAPICommand("web_summary", "summary")]
|
||||||
|
),
|
||||||
|
str(DataOptions.FAULT_LIGHT): DataFunction(
|
||||||
|
"get_fault_light", [WebAPICommand("web_summary", "summary")]
|
||||||
|
),
|
||||||
|
str(DataOptions.IS_MINING): DataFunction("is_mining"),
|
||||||
|
str(DataOptions.UPTIME): DataFunction(
|
||||||
|
"get_uptime", [WebAPICommand("web_summary", "summary")]
|
||||||
|
),
|
||||||
|
str(DataOptions.CONFIG): DataFunction("get_config"),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ePIC(BMMiner):
|
class ePIC(BaseMiner):
|
||||||
def __init__(self, ip: str, api_ver: str = "0.0.0") -> None:
|
def __init__(self, ip: str, api_ver: str = "0.0.0") -> None:
|
||||||
super().__init__(ip, api_ver)
|
super().__init__(ip, api_ver)
|
||||||
# interfaces
|
# interfaces
|
||||||
@@ -128,13 +150,13 @@ class ePIC(BMMiner):
|
|||||||
pass
|
pass
|
||||||
return False
|
return False
|
||||||
|
|
||||||
async def get_mac(self, web_summary: dict = None) -> str:
|
async def get_mac(self, web_network: dict = None) -> str:
|
||||||
if not web_summary:
|
if not web_network:
|
||||||
web_summary = await self.web.network()
|
web_network = await self.web.network()
|
||||||
if web_summary:
|
if web_network:
|
||||||
try:
|
try:
|
||||||
for network in web_summary:
|
for network in web_network:
|
||||||
mac = web_summary[network]["mac_address"]
|
mac = web_network[network]["mac_address"]
|
||||||
return mac
|
return mac
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
@@ -267,32 +289,6 @@ class ePIC(BMMiner):
|
|||||||
async def is_mining(self, *args, **kwargs) -> Optional[bool]:
|
async def is_mining(self, *args, **kwargs) -> Optional[bool]:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
async def get_pools(self, web_summary: dict = None) -> List[dict]:
|
|
||||||
groups = []
|
|
||||||
|
|
||||||
if not web_summary:
|
|
||||||
try:
|
|
||||||
web_summary = await self.api.summary()
|
|
||||||
except APIError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if web_summary:
|
|
||||||
try:
|
|
||||||
pools = {}
|
|
||||||
for i, pool in enumerate(web_summary["StratumConfigs"]):
|
|
||||||
pools[f"pool_{i + 1}_url"] = (
|
|
||||||
pool["pool"]
|
|
||||||
.replace("stratum+tcp://", "")
|
|
||||||
.replace("stratum2+tcp://", "")
|
|
||||||
)
|
|
||||||
pools[f"pool_{i + 1}_user"] = pool["login"]
|
|
||||||
pools["quota"] = pool["Quota"] if pool.get("Quota") else "0"
|
|
||||||
|
|
||||||
groups.append(pools)
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
return groups
|
|
||||||
|
|
||||||
async def get_uptime(self, web_summary: dict = None) -> Optional[int]:
|
async def get_uptime(self, web_summary: dict = None) -> Optional[int]:
|
||||||
if not web_summary:
|
if not web_summary:
|
||||||
web_summary = await self.web.summary()
|
web_summary = await self.web.summary()
|
||||||
@@ -328,3 +324,33 @@ class ePIC(BMMiner):
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
return errors
|
return errors
|
||||||
|
|
||||||
|
def fault_light_off(self) -> bool:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def fault_light_on(self) -> bool:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_api_ver(self, *args, **kwargs) -> Optional[str]:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_config(self) -> MinerConfig:
|
||||||
|
return self.config
|
||||||
|
|
||||||
|
def get_env_temp(self, *args, **kwargs) -> Optional[float]:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_fan_psu(self, *args, **kwargs) -> Optional[int]:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_version(self, *args, **kwargs) -> Tuple[Optional[str], Optional[str]]:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_wattage_limit(self, *args, **kwargs) -> Optional[int]:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def send_config(self, config: MinerConfig, user_suffix: str = None) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def set_power_limit(self, wattage: int) -> bool:
|
||||||
|
return False
|
||||||
|
|||||||
@@ -26,30 +26,52 @@ from pyasic.config import MinerConfig
|
|||||||
from pyasic.data import Fan, HashBoard
|
from pyasic.data import Fan, HashBoard
|
||||||
from pyasic.data.error_codes import BraiinsOSError, MinerErrorData
|
from pyasic.data.error_codes import BraiinsOSError, MinerErrorData
|
||||||
from pyasic.errors import APIError
|
from pyasic.errors import APIError
|
||||||
from pyasic.miners.base import BaseMiner
|
from pyasic.miners.base import (
|
||||||
|
BaseMiner,
|
||||||
|
DataFunction,
|
||||||
|
DataLocations,
|
||||||
|
DataOptions,
|
||||||
|
RPCAPICommand,
|
||||||
|
WebAPICommand,
|
||||||
|
)
|
||||||
from pyasic.web.bosminer import BOSMinerWebAPI
|
from pyasic.web.bosminer import BOSMinerWebAPI
|
||||||
|
|
||||||
LUXMINER_DATA_LOC = {
|
LUXMINER_DATA_LOC = DataLocations(
|
||||||
"mac": {"cmd": "get_mac", "kwargs": {"api_config": {"api": "config"}}},
|
**{
|
||||||
"model": {"cmd": "get_model", "kwargs": {}},
|
str(DataOptions.MAC): DataFunction(
|
||||||
"api_ver": {"cmd": "get_api_ver", "kwargs": {}},
|
"get_mac", [RPCAPICommand("api_config", "config")]
|
||||||
"fw_ver": {"cmd": "get_fw_ver", "kwargs": {}},
|
),
|
||||||
"hostname": {"cmd": "get_hostname", "kwargs": {}},
|
str(DataOptions.MODEL): DataFunction("get_model"),
|
||||||
"hashrate": {"cmd": "get_hashrate", "kwargs": {}},
|
str(DataOptions.API_VERSION): DataFunction("get_api_ver"),
|
||||||
"expected_hashrate": {"cmd": "get_expected_hashrate", "kwargs": {}},
|
str(DataOptions.FW_VERSION): DataFunction("get_fw_ver"),
|
||||||
"hashboards": {"cmd": "get_hashboards", "kwargs": {}},
|
str(DataOptions.HOSTNAME): DataFunction("get_hostname"),
|
||||||
"wattage": {"cmd": "get_wattage", "kwargs": {}},
|
str(DataOptions.HASHRATE): DataFunction(
|
||||||
"wattage_limit": {"cmd": "get_wattage_limit", "kwargs": {}},
|
"get_hashrate", [RPCAPICommand("api_summary", "summary")]
|
||||||
"fans": {"cmd": "get_fans", "kwargs": {}},
|
),
|
||||||
"fan_psu": {"cmd": "get_fan_psu", "kwargs": {}},
|
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
|
||||||
"env_temp": {"cmd": "get_env_temp", "kwargs": {}},
|
"get_expected_hashrate", [RPCAPICommand("api_stats", "stats")]
|
||||||
"errors": {"cmd": "get_errors", "kwargs": {}},
|
),
|
||||||
"fault_light": {"cmd": "get_fault_light", "kwargs": {}},
|
str(DataOptions.HASHBOARDS): DataFunction(
|
||||||
"pools": {"cmd": "get_pools", "kwargs": {}},
|
"get_hashboards", [RPCAPICommand("api_stats", "stats")]
|
||||||
"is_mining": {"cmd": "is_mining", "kwargs": {}},
|
),
|
||||||
"uptime": {"cmd": "get_uptime", "kwargs": {"api_stats": {"api": "stats"}}},
|
str(DataOptions.ENVIRONMENT_TEMP): DataFunction("get_env_temp"),
|
||||||
"config": {"cmd": "get_config", "kwargs": {}},
|
str(DataOptions.WATTAGE): DataFunction(
|
||||||
}
|
"get_wattage", [RPCAPICommand("api_power", "power")]
|
||||||
|
),
|
||||||
|
str(DataOptions.WATTAGE_LIMIT): DataFunction("get_wattage_limit"),
|
||||||
|
str(DataOptions.FANS): DataFunction(
|
||||||
|
"get_fans", [RPCAPICommand("api_fans", "fans")]
|
||||||
|
),
|
||||||
|
str(DataOptions.FAN_PSU): DataFunction("get_fan_psu"),
|
||||||
|
str(DataOptions.ERRORS): DataFunction("get_errors"),
|
||||||
|
str(DataOptions.FAULT_LIGHT): DataFunction("get_fault_light"),
|
||||||
|
str(DataOptions.IS_MINING): DataFunction("is_mining"),
|
||||||
|
str(DataOptions.UPTIME): DataFunction(
|
||||||
|
"get_uptime", [RPCAPICommand("api_stats", "stats")]
|
||||||
|
),
|
||||||
|
str(DataOptions.CONFIG): DataFunction("get_config"),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class LUXMiner(BaseMiner):
|
class LUXMiner(BaseMiner):
|
||||||
@@ -85,7 +107,6 @@ class LUXMiner(BaseMiner):
|
|||||||
return
|
return
|
||||||
|
|
||||||
async def fault_light_on(self) -> bool:
|
async def fault_light_on(self) -> bool:
|
||||||
"""Sends command to turn on fault light on the miner."""
|
|
||||||
try:
|
try:
|
||||||
session_id = await self._get_session()
|
session_id = await self._get_session()
|
||||||
if session_id:
|
if session_id:
|
||||||
@@ -96,7 +117,6 @@ class LUXMiner(BaseMiner):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
async def fault_light_off(self) -> bool:
|
async def fault_light_off(self) -> bool:
|
||||||
"""Sends command to turn off fault light on the miner."""
|
|
||||||
try:
|
try:
|
||||||
session_id = await self._get_session()
|
session_id = await self._get_session()
|
||||||
if session_id:
|
if session_id:
|
||||||
@@ -107,11 +127,9 @@ class LUXMiner(BaseMiner):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
async def restart_backend(self) -> bool:
|
async def restart_backend(self) -> bool:
|
||||||
"""Restart luxminer hashing process. Wraps [`restart_luxminer`][pyasic.miners.backends.luxminer.LUXMiner.restart_luxminer] to standardize."""
|
|
||||||
return await self.restart_luxminer()
|
return await self.restart_luxminer()
|
||||||
|
|
||||||
async def restart_luxminer(self) -> bool:
|
async def restart_luxminer(self) -> bool:
|
||||||
"""Restart luxminer hashing process."""
|
|
||||||
try:
|
try:
|
||||||
session_id = await self._get_session()
|
session_id = await self._get_session()
|
||||||
if session_id:
|
if session_id:
|
||||||
@@ -141,7 +159,6 @@ class LUXMiner(BaseMiner):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
async def reboot(self) -> bool:
|
async def reboot(self) -> bool:
|
||||||
"""Reboots power to the physical miner."""
|
|
||||||
try:
|
try:
|
||||||
session_id = await self._get_session()
|
session_id = await self._get_session()
|
||||||
if session_id:
|
if session_id:
|
||||||
@@ -303,56 +320,6 @@ class LUXMiner(BaseMiner):
|
|||||||
async def get_fan_psu(self) -> Optional[int]:
|
async def get_fan_psu(self) -> Optional[int]:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
async def get_pools(self, api_pools: dict = None) -> List[dict]:
|
|
||||||
if not api_pools:
|
|
||||||
try:
|
|
||||||
api_pools = await self.api.pools()
|
|
||||||
except APIError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if api_pools:
|
|
||||||
seen = []
|
|
||||||
groups = [{"quota": "0"}]
|
|
||||||
if api_pools.get("POOLS"):
|
|
||||||
for i, pool in enumerate(api_pools["POOLS"]):
|
|
||||||
if len(seen) == 0:
|
|
||||||
seen.append(pool["User"])
|
|
||||||
if not pool["User"] in seen:
|
|
||||||
# need to use get_config, as this will never read perfectly as there are some bad edge cases
|
|
||||||
groups = []
|
|
||||||
cfg = await self.get_config()
|
|
||||||
if cfg:
|
|
||||||
for group in cfg.pool_groups:
|
|
||||||
pools = {"quota": group.quota}
|
|
||||||
for _i, _pool in enumerate(group.pools):
|
|
||||||
pools[f"pool_{_i + 1}_url"] = _pool.url.replace(
|
|
||||||
"stratum+tcp://", ""
|
|
||||||
).replace("stratum2+tcp://", "")
|
|
||||||
pools[f"pool_{_i + 1}_user"] = _pool.username
|
|
||||||
groups.append(pools)
|
|
||||||
return groups
|
|
||||||
else:
|
|
||||||
groups[0][f"pool_{i + 1}_url"] = (
|
|
||||||
pool["URL"]
|
|
||||||
.replace("stratum+tcp://", "")
|
|
||||||
.replace("stratum2+tcp://", "")
|
|
||||||
)
|
|
||||||
groups[0][f"pool_{i + 1}_user"] = pool["User"]
|
|
||||||
else:
|
|
||||||
groups = []
|
|
||||||
cfg = await self.get_config()
|
|
||||||
if cfg:
|
|
||||||
for group in cfg.pool_groups:
|
|
||||||
pools = {"quota": group.quota}
|
|
||||||
for _i, _pool in enumerate(group.pools):
|
|
||||||
pools[f"pool_{_i + 1}_url"] = _pool.url.replace(
|
|
||||||
"stratum+tcp://", ""
|
|
||||||
).replace("stratum2+tcp://", "")
|
|
||||||
pools[f"pool_{_i + 1}_user"] = _pool.username
|
|
||||||
groups.append(pools)
|
|
||||||
return groups
|
|
||||||
return groups
|
|
||||||
|
|
||||||
async def get_errors(self) -> List[MinerErrorData]:
|
async def get_errors(self) -> List[MinerErrorData]:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -19,35 +19,57 @@ from typing import Optional
|
|||||||
from pyasic.errors import APIError
|
from pyasic.errors import APIError
|
||||||
from pyasic.logger import logger
|
from pyasic.logger import logger
|
||||||
from pyasic.miners.backends.bmminer import BMMiner
|
from pyasic.miners.backends.bmminer import BMMiner
|
||||||
|
from pyasic.miners.base import (
|
||||||
|
DataFunction,
|
||||||
|
DataLocations,
|
||||||
|
DataOptions,
|
||||||
|
RPCAPICommand,
|
||||||
|
WebAPICommand,
|
||||||
|
)
|
||||||
from pyasic.web.vnish import VNishWebAPI
|
from pyasic.web.vnish import VNishWebAPI
|
||||||
|
|
||||||
VNISH_DATA_LOC = {
|
VNISH_DATA_LOC = DataLocations(
|
||||||
"mac": {"cmd": "get_mac", "kwargs": {"web_summary": {"web": "summary"}}},
|
**{
|
||||||
"model": {"cmd": "get_model", "kwargs": {}},
|
str(DataOptions.MAC): DataFunction(
|
||||||
"api_ver": {"cmd": "get_api_ver", "kwargs": {"api_version": {"api": "version"}}},
|
"get_mac", [WebAPICommand("web_summary", "summary")]
|
||||||
"fw_ver": {"cmd": "get_fw_ver", "kwargs": {"web_summary": {"web": "summary"}}},
|
),
|
||||||
"hostname": {"cmd": "get_hostname", "kwargs": {"web_summary": {"web": "summary"}}},
|
str(DataOptions.MODEL): DataFunction("get_model"),
|
||||||
"hashrate": {"cmd": "get_hashrate", "kwargs": {"api_summary": {"api": "summary"}}},
|
str(DataOptions.API_VERSION): DataFunction(
|
||||||
"expected_hashrate": {
|
"get_api_ver", [RPCAPICommand("api_version", "version")]
|
||||||
"cmd": "get_expected_hashrate",
|
),
|
||||||
"kwargs": {"api_stats": {"api": "stats"}},
|
str(DataOptions.FW_VERSION): DataFunction(
|
||||||
},
|
"get_fw_ver", [WebAPICommand("web_summary", "summary")]
|
||||||
"hashboards": {"cmd": "get_hashboards", "kwargs": {"api_stats": {"api": "stats"}}},
|
),
|
||||||
"env_temp": {"cmd": "get_env_temp", "kwargs": {}},
|
str(DataOptions.HOSTNAME): DataFunction(
|
||||||
"wattage": {"cmd": "get_wattage", "kwargs": {"web_summary": {"web": "summary"}}},
|
"get_hostname", [WebAPICommand("web_summary", "summary")]
|
||||||
"wattage_limit": {
|
),
|
||||||
"cmd": "get_wattage_limit",
|
str(DataOptions.HASHRATE): DataFunction(
|
||||||
"kwargs": {"web_settings": {"web": "settings"}},
|
"get_hashrate", [WebAPICommand("web_summary", "summary")]
|
||||||
},
|
),
|
||||||
"fans": {"cmd": "get_fans", "kwargs": {"api_stats": {"api": "stats"}}},
|
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
|
||||||
"fan_psu": {"cmd": "get_fan_psu", "kwargs": {}},
|
"get_expected_hashrate", [RPCAPICommand("api_stats", "stats")]
|
||||||
"errors": {"cmd": "get_errors", "kwargs": {}},
|
),
|
||||||
"fault_light": {"cmd": "get_fault_light", "kwargs": {}},
|
str(DataOptions.HASHBOARDS): DataFunction(
|
||||||
"pools": {"cmd": "get_pools", "kwargs": {"api_pools": {"api": "pools"}}},
|
"get_hashboards", [RPCAPICommand("api_stats", "stats")]
|
||||||
"is_mining": {"cmd": "is_mining", "kwargs": {}},
|
),
|
||||||
"uptime": {"cmd": "get_uptime", "kwargs": {}},
|
str(DataOptions.ENVIRONMENT_TEMP): DataFunction("get_env_temp"),
|
||||||
"config": {"cmd": "get_config", "kwargs": {}},
|
str(DataOptions.WATTAGE): DataFunction(
|
||||||
}
|
"get_wattage", [WebAPICommand("web_summary", "summary")]
|
||||||
|
),
|
||||||
|
str(DataOptions.WATTAGE_LIMIT): DataFunction(
|
||||||
|
"get_wattage_limit", [WebAPICommand("web_settings", "settings")]
|
||||||
|
),
|
||||||
|
str(DataOptions.FANS): DataFunction(
|
||||||
|
"get_fans", [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):
|
class VNish(BMMiner):
|
||||||
|
|||||||
@@ -17,7 +17,9 @@ import asyncio
|
|||||||
import ipaddress
|
import ipaddress
|
||||||
import logging
|
import logging
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
from typing import List, Optional, Tuple, TypeVar
|
from dataclasses import dataclass, field, make_dataclass
|
||||||
|
from enum import Enum
|
||||||
|
from typing import List, Optional, Tuple, TypeVar, Union
|
||||||
|
|
||||||
import asyncssh
|
import asyncssh
|
||||||
|
|
||||||
@@ -27,6 +29,70 @@ from pyasic.data.error_codes import MinerErrorData
|
|||||||
from pyasic.logger import logger
|
from pyasic.logger import logger
|
||||||
|
|
||||||
|
|
||||||
|
class DataOptions(Enum):
|
||||||
|
MAC = "mac"
|
||||||
|
MODEL = "model"
|
||||||
|
API_VERSION = "api_ver"
|
||||||
|
FW_VERSION = "fw_ver"
|
||||||
|
HOSTNAME = "hostname"
|
||||||
|
HASHRATE = "hashrate"
|
||||||
|
EXPECTED_HASHRATE = "expected_hashrate"
|
||||||
|
HASHBOARDS = "hashboards"
|
||||||
|
ENVIRONMENT_TEMP = "env_temp"
|
||||||
|
WATTAGE = "wattage"
|
||||||
|
WATTAGE_LIMIT = "wattage_limit"
|
||||||
|
FANS = "fans"
|
||||||
|
FAN_PSU = "fan_psu"
|
||||||
|
ERRORS = "errors"
|
||||||
|
FAULT_LIGHT = "fault_light"
|
||||||
|
IS_MINING = "is_mining"
|
||||||
|
UPTIME = "uptime"
|
||||||
|
CONFIG = "config"
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.value
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class RPCAPICommand:
|
||||||
|
name: str
|
||||||
|
cmd: str
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class WebAPICommand:
|
||||||
|
name: str
|
||||||
|
cmd: str
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class GRPCCommand(WebAPICommand):
|
||||||
|
name: str
|
||||||
|
cmd: str
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class GraphQLCommand(WebAPICommand):
|
||||||
|
name: str
|
||||||
|
cmd: dict
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class DataFunction:
|
||||||
|
cmd: str
|
||||||
|
kwargs: list[
|
||||||
|
Union[RPCAPICommand, WebAPICommand, GRPCCommand, GraphQLCommand]
|
||||||
|
] = field(default_factory=list)
|
||||||
|
|
||||||
|
|
||||||
|
DataLocations = make_dataclass(
|
||||||
|
"DataLocations",
|
||||||
|
[(enum_value.value, str) for enum_value in DataOptions],
|
||||||
|
)
|
||||||
|
# add default value with
|
||||||
|
# [(enum_value.value, str, , DataFunction(enum_value.value)) for enum_value in DataOptions],
|
||||||
|
|
||||||
|
|
||||||
class BaseMiner(ABC):
|
class BaseMiner(ABC):
|
||||||
def __init__(self, ip: str, *args, **kwargs) -> None:
|
def __init__(self, ip: str, *args, **kwargs) -> None:
|
||||||
# interfaces
|
# interfaces
|
||||||
@@ -46,7 +112,7 @@ class BaseMiner(ABC):
|
|||||||
self.expected_chips = 0
|
self.expected_chips = 0
|
||||||
self.fan_count = 2
|
self.fan_count = 2
|
||||||
# data gathering locations
|
# data gathering locations
|
||||||
self.data_locations = None
|
self.data_locations: DataLocations = None
|
||||||
# autotuning/shutdown support
|
# autotuning/shutdown support
|
||||||
self.supports_autotuning = False
|
self.supports_autotuning = False
|
||||||
self.supports_shutdown = False
|
self.supports_shutdown = False
|
||||||
@@ -359,15 +425,6 @@ class BaseMiner(ABC):
|
|||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
async def get_pools(self, *args, **kwargs) -> List[dict]:
|
|
||||||
"""Get pool information from the miner.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Pool groups and quotas in a list of dicts.
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
async def get_errors(self, *args, **kwargs) -> List[MinerErrorData]:
|
async def get_errors(self, *args, **kwargs) -> List[MinerErrorData]:
|
||||||
"""Get a list of the errors the miner is experiencing.
|
"""Get a list of the errors the miner is experiencing.
|
||||||
@@ -414,28 +471,33 @@ class BaseMiner(ABC):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
async def _get_data(
|
async def _get_data(
|
||||||
self, allow_warning: bool, include: list = None, exclude: list = None
|
self,
|
||||||
|
allow_warning: bool,
|
||||||
|
include: List[Union[str, DataOptions]] = None,
|
||||||
|
exclude: List[Union[str, DataOptions]] = None,
|
||||||
) -> dict:
|
) -> dict:
|
||||||
if include is None:
|
if include is not None:
|
||||||
|
include = [str(i) for i in include]
|
||||||
|
else:
|
||||||
# everything
|
# everything
|
||||||
include = list(self.data_locations.keys())
|
include = [str(enum_value.value) for enum_value in DataOptions]
|
||||||
|
|
||||||
if exclude is not None:
|
if exclude is not None:
|
||||||
for item in exclude:
|
for item in exclude:
|
||||||
if item in include:
|
if str(item) in include:
|
||||||
include.remove(item)
|
include.remove(str(item))
|
||||||
|
|
||||||
api_multicommand = set()
|
api_multicommand = set()
|
||||||
web_multicommand = []
|
web_multicommand = []
|
||||||
for data_name in include:
|
for data_name in include:
|
||||||
try:
|
try:
|
||||||
fn_args = self.data_locations[data_name]["kwargs"]
|
fn_args = getattr(self.data_locations, data_name).kwargs
|
||||||
for arg_name in fn_args:
|
for arg in fn_args:
|
||||||
if fn_args[arg_name].get("api"):
|
if isinstance(arg, RPCAPICommand):
|
||||||
api_multicommand.add(fn_args[arg_name]["api"])
|
api_multicommand.add(arg.cmd)
|
||||||
if fn_args[arg_name].get("web"):
|
if isinstance(arg, WebAPICommand):
|
||||||
if not fn_args[arg_name]["web"] in web_multicommand:
|
if arg.cmd not in web_multicommand:
|
||||||
web_multicommand.append(fn_args[arg_name]["web"])
|
web_multicommand.append(arg.cmd)
|
||||||
except KeyError as e:
|
except KeyError as e:
|
||||||
logger.error(e, data_name)
|
logger.error(e, data_name)
|
||||||
continue
|
continue
|
||||||
@@ -465,37 +527,36 @@ class BaseMiner(ABC):
|
|||||||
|
|
||||||
for data_name in include:
|
for data_name in include:
|
||||||
try:
|
try:
|
||||||
fn_args = self.data_locations[data_name]["kwargs"]
|
fn_args = getattr(self.data_locations, data_name).kwargs
|
||||||
args_to_send = {k: None for k in fn_args}
|
args_to_send = {k.name: None for k in fn_args}
|
||||||
for arg_name in fn_args:
|
for arg in fn_args:
|
||||||
try:
|
try:
|
||||||
if fn_args[arg_name].get("api"):
|
if isinstance(arg, RPCAPICommand):
|
||||||
if api_command_data.get("multicommand"):
|
if api_command_data.get("multicommand"):
|
||||||
args_to_send[arg_name] = api_command_data[
|
args_to_send[arg.name] = api_command_data[arg.cmd][0]
|
||||||
fn_args[arg_name]["api"]
|
|
||||||
][0]
|
|
||||||
else:
|
else:
|
||||||
args_to_send[arg_name] = api_command_data
|
args_to_send[arg.name] = api_command_data
|
||||||
if fn_args[arg_name].get("web"):
|
if isinstance(arg, WebAPICommand):
|
||||||
if web_command_data is not None:
|
if web_command_data is not None:
|
||||||
if web_command_data.get("multicommand"):
|
if web_command_data.get("multicommand"):
|
||||||
args_to_send[arg_name] = web_command_data[
|
args_to_send[arg.name] = web_command_data[arg.cmd]
|
||||||
fn_args[arg_name]["web"]
|
|
||||||
]
|
|
||||||
else:
|
else:
|
||||||
if not web_command_data == {"multicommand": False}:
|
if not web_command_data == {"multicommand": False}:
|
||||||
args_to_send[arg_name] = web_command_data
|
args_to_send[arg.name] = web_command_data
|
||||||
except LookupError:
|
except LookupError:
|
||||||
args_to_send[arg_name] = None
|
args_to_send[arg.name] = None
|
||||||
except LookupError:
|
except LookupError:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
function = getattr(self, self.data_locations[data_name]["cmd"])
|
function = getattr(self, getattr(self.data_locations, data_name).cmd)
|
||||||
miner_data[data_name] = await function(**args_to_send)
|
miner_data[data_name] = await function(**args_to_send)
|
||||||
return miner_data
|
return miner_data
|
||||||
|
|
||||||
async def get_data(
|
async def get_data(
|
||||||
self, allow_warning: bool = False, include: list = None, exclude: list = None
|
self,
|
||||||
|
allow_warning: bool = False,
|
||||||
|
include: List[Union[str, DataOptions]] = None,
|
||||||
|
exclude: List[Union[str, DataOptions]] = None,
|
||||||
) -> MinerData:
|
) -> MinerData:
|
||||||
"""Get data from the miner in the form of [`MinerData`][pyasic.data.MinerData].
|
"""Get data from the miner in the form of [`MinerData`][pyasic.data.MinerData].
|
||||||
|
|
||||||
|
|||||||
@@ -267,32 +267,6 @@ class CGMinerA10X(CGMiner, A10X):
|
|||||||
|
|
||||||
return fans
|
return fans
|
||||||
|
|
||||||
async def get_pools(self, api_pools: dict = None) -> List[dict]:
|
|
||||||
groups = []
|
|
||||||
|
|
||||||
if not api_pools:
|
|
||||||
try:
|
|
||||||
api_pools = await self.api.pools()
|
|
||||||
except APIError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if api_pools:
|
|
||||||
try:
|
|
||||||
pools = {}
|
|
||||||
for i, pool in enumerate(api_pools["POOLS"]):
|
|
||||||
pools[f"pool_{i + 1}_url"] = (
|
|
||||||
pool["URL"]
|
|
||||||
.replace("stratum+tcp://", "")
|
|
||||||
.replace("stratum2+tcp://", "")
|
|
||||||
)
|
|
||||||
pools[f"pool_{i + 1}_user"] = pool["User"]
|
|
||||||
pools["quota"] = pool["Quota"] if pool.get("Quota") else "0"
|
|
||||||
|
|
||||||
groups.append(pools)
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
return groups
|
|
||||||
|
|
||||||
async def get_errors(
|
async def get_errors(
|
||||||
self, web_get_error_detail: dict = None
|
self, web_get_error_detail: dict = None
|
||||||
) -> List[MinerErrorData]: # noqa: named this way for automatic functionality
|
) -> List[MinerErrorData]: # noqa: named this way for automatic functionality
|
||||||
|
|||||||
@@ -246,32 +246,6 @@ class CGMinerT3HPlus(CGMiner, T3HPlus):
|
|||||||
|
|
||||||
return fans
|
return fans
|
||||||
|
|
||||||
async def get_pools(self, api_pools: dict = None) -> List[dict]:
|
|
||||||
groups = []
|
|
||||||
|
|
||||||
if not api_pools:
|
|
||||||
try:
|
|
||||||
api_pools = await self.api.pools()
|
|
||||||
except APIError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if api_pools:
|
|
||||||
try:
|
|
||||||
pools = {}
|
|
||||||
for i, pool in enumerate(api_pools["POOLS"]):
|
|
||||||
pools[f"pool_{i + 1}_url"] = (
|
|
||||||
pool["URL"]
|
|
||||||
.replace("stratum+tcp://", "")
|
|
||||||
.replace("stratum2+tcp://", "")
|
|
||||||
)
|
|
||||||
pools[f"pool_{i + 1}_user"] = pool["User"]
|
|
||||||
pools["quota"] = pool["Quota"] if pool.get("Quota") else "0"
|
|
||||||
|
|
||||||
groups.append(pools)
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
return groups
|
|
||||||
|
|
||||||
async def get_errors(
|
async def get_errors(
|
||||||
self, web_get_error_detail: dict = None
|
self, web_get_error_detail: dict = None
|
||||||
) -> List[MinerErrorData]: # noqa: named this way for automatic functionality
|
) -> List[MinerErrorData]: # noqa: named this way for automatic functionality
|
||||||
|
|||||||
@@ -113,32 +113,6 @@ class UnknownMiner(BaseMiner):
|
|||||||
async def get_fw_ver(self) -> Optional[str]:
|
async def get_fw_ver(self) -> Optional[str]:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
async def get_pools(self, api_pools: dict = None) -> List[dict]:
|
|
||||||
groups = []
|
|
||||||
|
|
||||||
if not api_pools:
|
|
||||||
try:
|
|
||||||
api_pools = await self.api.pools()
|
|
||||||
except APIError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if api_pools:
|
|
||||||
try:
|
|
||||||
pools = {}
|
|
||||||
for i, pool in enumerate(api_pools["POOLS"]):
|
|
||||||
pools[f"pool_{i + 1}_url"] = (
|
|
||||||
pool["URL"]
|
|
||||||
.replace("stratum+tcp://", "")
|
|
||||||
.replace("stratum2+tcp://", "")
|
|
||||||
)
|
|
||||||
pools[f"pool_{i + 1}_user"] = pool["User"]
|
|
||||||
pools["quota"] = pool["Quota"] if pool.get("Quota") else "0"
|
|
||||||
|
|
||||||
groups.append(pools)
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
return groups
|
|
||||||
|
|
||||||
async def get_errors(self) -> List[MinerErrorData]:
|
async def get_errors(self) -> List[MinerErrorData]:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
@@ -155,6 +129,6 @@ class UnknownMiner(BaseMiner):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
async def get_data(
|
async def get_data(
|
||||||
self, allow_warning: bool = False, data_to_get: list = None
|
self, allow_warning: bool = False, data_to_get: list = None, **kwargs
|
||||||
) -> MinerData:
|
) -> MinerData:
|
||||||
return MinerData(ip=str(self.ip))
|
return MinerData(ip=str(self.ip))
|
||||||
|
|||||||
@@ -123,9 +123,8 @@ class MinerNetwork:
|
|||||||
# clear cached miners
|
# clear cached miners
|
||||||
miner_factory.clear_cached_miners()
|
miner_factory.clear_cached_miners()
|
||||||
|
|
||||||
limit = asyncio.Semaphore(settings.get("network_scan_threads", 300))
|
|
||||||
miners = await asyncio.gather(
|
miners = await asyncio.gather(
|
||||||
*[self.ping_and_get_miner(host, limit) for host in self.hosts]
|
*[self.ping_and_get_miner(host) for host in self.hosts]
|
||||||
)
|
)
|
||||||
|
|
||||||
# remove all None from the miner list
|
# remove all None from the miner list
|
||||||
@@ -148,12 +147,8 @@ class MinerNetwork:
|
|||||||
loop = asyncio.get_event_loop()
|
loop = asyncio.get_event_loop()
|
||||||
|
|
||||||
# create a list of scan tasks
|
# create a list of scan tasks
|
||||||
limit = asyncio.Semaphore(settings.get("network_scan_threads", 300))
|
|
||||||
miners = asyncio.as_completed(
|
miners = asyncio.as_completed(
|
||||||
[
|
[loop.create_task(self.ping_and_get_miner(host)) for host in self.hosts]
|
||||||
loop.create_task(self.ping_and_get_miner(host, limit))
|
|
||||||
for host in self.hosts
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
for miner in miners:
|
for miner in miners:
|
||||||
try:
|
try:
|
||||||
@@ -162,21 +157,16 @@ class MinerNetwork:
|
|||||||
yield None
|
yield None
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def ping_and_get_miner(
|
async def ping_and_get_miner(ip: ipaddress.ip_address) -> Union[None, AnyMiner]:
|
||||||
ip: ipaddress.ip_address, semaphore: asyncio.Semaphore
|
try:
|
||||||
) -> Union[None, AnyMiner]:
|
return await ping_and_get_miner(ip)
|
||||||
async with semaphore:
|
except ConnectionRefusedError:
|
||||||
try:
|
tasks = [ping_and_get_miner(ip, port=port) for port in [4028, 4029, 8889]]
|
||||||
return await ping_and_get_miner(ip)
|
for miner in asyncio.as_completed(tasks):
|
||||||
except ConnectionRefusedError:
|
try:
|
||||||
tasks = [
|
return await miner
|
||||||
ping_and_get_miner(ip, port=port) for port in [4028, 4029, 8889]
|
except ConnectionRefusedError:
|
||||||
]
|
pass
|
||||||
for miner in asyncio.as_completed(tasks):
|
|
||||||
try:
|
|
||||||
return await miner
|
|
||||||
except ConnectionRefusedError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
async def ping_and_get_miner(
|
async def ping_and_get_miner(
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ from httpx import AsyncHTTPTransport
|
|||||||
_settings = { # defaults
|
_settings = { # defaults
|
||||||
"network_ping_retries": 1,
|
"network_ping_retries": 1,
|
||||||
"network_ping_timeout": 3,
|
"network_ping_timeout": 3,
|
||||||
"network_scan_threads": 300,
|
|
||||||
"factory_get_retries": 1,
|
"factory_get_retries": 1,
|
||||||
"factory_get_timeout": 3,
|
"factory_get_timeout": 3,
|
||||||
"get_data_retries": 1,
|
"get_data_retries": 1,
|
||||||
|
|||||||
@@ -10,10 +10,10 @@ readme = "README.md"
|
|||||||
[tool.poetry.dependencies]
|
[tool.poetry.dependencies]
|
||||||
python = "^3.8"
|
python = "^3.8"
|
||||||
httpx = "^0.26.0"
|
httpx = "^0.26.0"
|
||||||
asyncssh = "^2.14.1"
|
asyncssh = "^2.14.2"
|
||||||
grpc-requests = "^0.1.12"
|
grpc-requests = "^0.1.13"
|
||||||
passlib = "^1.7.4"
|
passlib = "^1.7.4"
|
||||||
pyaml = "^23.9.7"
|
pyaml = "^23.12.0"
|
||||||
toml = "^0.10.2"
|
toml = "^0.10.2"
|
||||||
betterproto = "2.0.0b6"
|
betterproto = "2.0.0b6"
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import inspect
|
|||||||
import sys
|
import sys
|
||||||
import unittest
|
import unittest
|
||||||
import warnings
|
import warnings
|
||||||
|
from dataclasses import asdict
|
||||||
|
|
||||||
from pyasic.miners.backends import CGMiner # noqa
|
from pyasic.miners.backends import CGMiner # noqa
|
||||||
from pyasic.miners.base import BaseMiner
|
from pyasic.miners.base import BaseMiner
|
||||||
@@ -57,7 +58,6 @@ class MinersTest(unittest.TestCase):
|
|||||||
"mac",
|
"mac",
|
||||||
"model",
|
"model",
|
||||||
"expected_hashrate",
|
"expected_hashrate",
|
||||||
"pools",
|
|
||||||
"uptime",
|
"uptime",
|
||||||
"wattage",
|
"wattage",
|
||||||
"wattage_limit",
|
"wattage_limit",
|
||||||
@@ -72,7 +72,9 @@ class MinersTest(unittest.TestCase):
|
|||||||
miner_api=miner_api,
|
miner_api=miner_api,
|
||||||
):
|
):
|
||||||
miner = MINER_CLASSES[miner_model][miner_api]("127.0.0.1")
|
miner = MINER_CLASSES[miner_model][miner_api]("127.0.0.1")
|
||||||
miner_keys = sorted(list(miner.data_locations.keys()))
|
miner_keys = sorted(
|
||||||
|
[str(k) for k in asdict(miner.data_locations).keys()]
|
||||||
|
)
|
||||||
self.assertEqual(miner_keys, keys)
|
self.assertEqual(miner_keys, keys)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user