Compare commits

..

11 Commits

Author SHA1 Message Date
Upstream Data
c8a8315ad0 version: bump version number. 2024-06-04 09:28:15 -06:00
Upstream Data
dac9bcc3de refactor: improve _get_data implementation slightly. 2024-06-04 08:53:25 -06:00
Brett Rowan
46621d6b93 Merge pull request #151 from Ytemiloluwa/master 2024-06-02 13:50:51 -06:00
ytemiloluwa
35700f7e57 pools: MinerData 2024-06-02 20:47:58 +01:00
ytemiloluwa
08e6744595 index: unused variable 2024-06-02 07:26:43 +01:00
ytemiloluwa
2de3e5e328 update: _get_pools method 2024-06-02 07:13:39 +01:00
Temi
51f2eb1b1d Merge branch 'UpstreamData:master' into master 2024-06-02 06:51:28 +01:00
ytemiloluwa
521853863b base: _get_pools and get_pools 2024-05-26 13:21:53 +01:00
ytemiloluwa
b7a5a647b3 pools: DATA LOC 2024-05-26 00:36:07 +01:00
ytemiloluwa
4434f9ccad get_data: kwarg key 2024-05-26 00:22:57 +01:00
ytemiloluwa
82a1cc3cfe backends: _get_pools in antminer 2024-05-25 23:08:33 +01:00
6 changed files with 79 additions and 16 deletions

View File

@@ -29,6 +29,7 @@ from .device import DeviceInfo
from .error_codes import BraiinsOSError, InnosiliconError, WhatsminerError, X19Error
from .fans import Fan
from .hashrate import AlgoHashRate, HashUnit
from pyasic.data.pools import PoolMetrics
@dataclass
@@ -71,6 +72,7 @@ class MinerData:
fault_light: Whether the fault light is on as a boolean.
efficiency: Efficiency of the miner in J/TH (Watts per TH/s). Calculated automatically.
is_mining: Whether the miner is mining.
pools: A list of PoolMetrics instances, each representing metrics for a pool.
"""
# general
@@ -143,6 +145,9 @@ class MinerData:
uptime: int = None
efficiency: int = field(init=False)
# pools
pools: list[PoolMetrics] = field(default_factory=list)
@classmethod
def fields(cls):
return [f.name for f in fields(cls) if not f.name.startswith("_")]

View File

@@ -19,7 +19,6 @@ from typing import List, Optional, Union
from pyasic.config import MinerConfig, MiningModeConfig
from pyasic.data import AlgoHashRate, Fan, HashBoard, HashUnit
from pyasic.data.error_codes import MinerErrorData, X19Error
from pyasic.errors import APIError
from pyasic.miners.backends.bmminer import BMMiner
from pyasic.miners.backends.cgminer import CGMiner
from pyasic.miners.data import (
@@ -32,6 +31,8 @@ from pyasic.miners.data import (
from pyasic.rpc.antminer import AntminerRPCAPI
from pyasic.ssh.antminer import AntminerModernSSH
from pyasic.web.antminer import AntminerModernWebAPI, AntminerOldWebAPI
from pyasic.data.pools import PoolMetrics
from pyasic.errors import APIError
ANTMINER_MODERN_DATA_LOC = DataLocations(
**{
@@ -79,6 +80,10 @@ ANTMINER_MODERN_DATA_LOC = DataLocations(
"_get_uptime",
[RPCAPICommand("rpc_stats", "stats")],
),
str(DataOptions.POOLS): DataFunction(
"_get_pools",
[RPCAPICommand("rpc_pools", "pools")],
),
}
)
@@ -351,6 +356,35 @@ class AntminerModern(BMMiner):
except LookupError:
pass
async def _get_pools(self, rpc_pools: dict = None) -> List[PoolMetrics]:
if rpc_pools is None:
try:
rpc_pools = await self.rpc.pools()
except APIError:
pass
pools_data = []
if rpc_pools is not None:
try:
pools = rpc_pools.get("POOLS", [])
for pool_info in pools:
pool_data = PoolMetrics(
accepted=pool_info.get("Accepted"),
rejected=pool_info.get("Rejected"),
get_failures=pool_info.get("Get Failures"),
remote_failures=pool_info.get("Remote Failures"),
active=pool_info.get("Stratum Active"),
alive=pool_info.get("Status") == "Alive",
url=pool_info.get("URL"),
user=pool_info.get("User"),
index=pool_info.get("POOL")
)
pools_data.append(pool_data)
except LookupError:
pass
return pools_data
ANTMINER_OLD_DATA_LOC = DataLocations(
**{

View File

@@ -22,6 +22,7 @@ from pyasic.config import MinerConfig
from pyasic.data import Fan, HashBoard, MinerData
from pyasic.data.device import DeviceInfo
from pyasic.data.error_codes import MinerErrorData
from pyasic.data.pools import PoolMetrics
from pyasic.device import MinerModel
from pyasic.device.algorithm import MinerAlgo
from pyasic.device.firmware import MinerFirmware
@@ -341,6 +342,14 @@ class MinerProtocol(Protocol):
"""
return await self._get_uptime()
async def get_pools(self) -> List[PoolMetrics]:
"""Get the pools information from Miner.
Return:
The pool information of the miner.
"""
return await self._get_pools()
async def _get_mac(self) -> Optional[str]:
pass
@@ -392,56 +401,69 @@ class MinerProtocol(Protocol):
async def _get_uptime(self) -> Optional[int]:
pass
async def _get_pools(self) -> List[PoolMetrics]:
pass
async def _get_data(
self,
allow_warning: bool,
include: List[Union[str, DataOptions]] = None,
exclude: List[Union[str, DataOptions]] = None,
) -> dict:
# handle include
if include is not None:
include = [str(i) for i in include]
else:
# everything
include = [str(enum_value.value) for enum_value in DataOptions]
# handle exclude
# prioritized over include, including x and excluding x will exclude x
if exclude is not None:
for item in exclude:
if str(item) in include:
include.remove(str(item))
api_multicommand = set()
web_multicommand = []
rpc_multicommand = set()
web_multicommand = set()
# create multicommand
for data_name in include:
try:
# get kwargs needed for the _get_xyz function
fn_args = getattr(self.data_locations, data_name).kwargs
# keep track of which RPC/Web commands need to be sent
for arg in fn_args:
if isinstance(arg, RPCAPICommand):
api_multicommand.add(arg.cmd)
rpc_multicommand.add(arg.cmd)
if isinstance(arg, WebAPICommand):
if arg.cmd not in web_multicommand:
web_multicommand.append(arg.cmd)
web_multicommand.add(arg.cmd)
except KeyError as e:
logger.error(e, data_name)
logger.error(type(e), e, data_name)
continue
if len(api_multicommand) > 0:
api_command_task = asyncio.create_task(
self.api.multicommand(*api_multicommand, allow_warning=allow_warning)
# create tasks for all commands that need to be sent, or no-op with sleep(0) -> None
if len(rpc_multicommand) > 0:
rpc_command_task = asyncio.create_task(
self.rpc.multicommand(*rpc_multicommand, allow_warning=allow_warning)
)
else:
api_command_task = asyncio.sleep(0)
rpc_command_task = asyncio.create_task(asyncio.sleep(0))
if len(web_multicommand) > 0:
web_command_task = asyncio.create_task(
self.web.multicommand(*web_multicommand, allow_warning=allow_warning)
)
else:
web_command_task = asyncio.sleep(0)
web_command_task = asyncio.create_task(asyncio.sleep(0))
web_command_data = await web_command_task
# make sure the tasks complete
await asyncio.gather(rpc_command_task, web_command_task)
# grab data out of the tasks
web_command_data = web_command_task.result()
if web_command_data is None:
web_command_data = {}
api_command_data = await api_command_task
api_command_data = rpc_command_task.result()
if api_command_data is None:
api_command_data = {}

View File

@@ -38,6 +38,7 @@ class DataOptions(Enum):
UPTIME = "uptime"
CONFIG = "config"
VOLTAGE = "voltage"
POOLS = "pools"
def __str__(self):
return self.value

View File

@@ -1,6 +1,6 @@
[tool.poetry]
name = "pyasic"
version = "0.57.5"
version = "0.57.6"
description = "A simplified and standardized interface for Bitcoin ASICs."
authors = ["UpstreamData <brett@upstreamdata.ca>"]
repository = "https://github.com/UpstreamData/pyasic"

View File

@@ -57,6 +57,7 @@ class MinersTest(unittest.TestCase):
"wattage",
"voltage",
"wattage_limit",
"pools",
]
)
warnings.filterwarnings("ignore")