From 4d9fde572e81bd7d8fd18bd26e77de9a0c415a6c Mon Sep 17 00:00:00 2001 From: John-Paul Compagnone Date: Tue, 11 Jun 2024 11:10:07 -0400 Subject: [PATCH] feat: add voltage,tuned status to HB. Add pool_data to ePIC --- pyasic/config/mining/__init__.py | 2 +- pyasic/data/boards.py | 4 ++ pyasic/data/pools.py | 2 + pyasic/miners/backends/epic.py | 71 ++++++++++++++++++++++++-------- pyasic/miners/data.py | 1 - 5 files changed, 60 insertions(+), 20 deletions(-) diff --git a/pyasic/config/mining/__init__.py b/pyasic/config/mining/__init__.py index af99ce8b..790579fb 100644 --- a/pyasic/config/mining/__init__.py +++ b/pyasic/config/mining/__init__.py @@ -485,7 +485,7 @@ class MiningModeConfig(MinerConfigOption): return cls.hashrate_tuning( hashrate=algo_info["BoardTune"].get("Target"), - algo=TunerAlgo.voltage_optimizer(), + algo=TunerAlgo.board_tune(), scaling=scaling_cfg, ) else: diff --git a/pyasic/data/boards.py b/pyasic/data/boards.py index b501e16e..940ded83 100644 --- a/pyasic/data/boards.py +++ b/pyasic/data/boards.py @@ -33,6 +33,8 @@ class HashBoard: expected_chips: The expected chip count of the board as an int. serial_number: The serial number of the board. missing: Whether the board is returned from the miners data as a bool. + tuned: Whether the board is tuned as a bool. + voltage: Current input voltage of the board as a float. """ slot: int = 0 @@ -43,6 +45,8 @@ class HashBoard: expected_chips: int = None serial_number: str = None missing: bool = True + tuned: bool = True + voltage: float = None def get(self, __key: str, default: Any = None): try: diff --git a/pyasic/data/pools.py b/pyasic/data/pools.py index 4ff4e158..f8802a90 100644 --- a/pyasic/data/pools.py +++ b/pyasic/data/pools.py @@ -15,6 +15,7 @@ class PoolMetrics: url: URL of the pool. index: Index of the pool. user: Username for the pool. + latency: latency of pool connection in milliseconds. pool_rejected_percent: Percentage of rejected shares by the pool. pool_stale_percent: Percentage of stale shares by the pool. """ @@ -28,6 +29,7 @@ class PoolMetrics: url: str = None index: int = None user: str = None + latency: float = None pool_rejected_percent: float = field(init=False) pool_stale_percent: float = field(init=False) diff --git a/pyasic/miners/backends/epic.py b/pyasic/miners/backends/epic.py index e3134dfc..64ec43d2 100644 --- a/pyasic/miners/backends/epic.py +++ b/pyasic/miners/backends/epic.py @@ -21,6 +21,7 @@ from pyasic.data import AlgoHashRate, Fan, HashBoard, HashUnit from pyasic.data.error_codes import MinerErrorData, X19Error from pyasic.errors import APIError from pyasic.logger import logger +from pyasic.data.pools import PoolMetrics from pyasic.miners.data import DataFunction, DataLocations, DataOptions, WebAPICommand from pyasic.miners.device.firmware import ePICFirmware from pyasic.web.epic import ePICWebAPI @@ -58,10 +59,6 @@ EPIC_DATA_LOC = DataLocations( "_get_wattage", [WebAPICommand("web_summary", "summary")], ), - str(DataOptions.VOLTAGE): DataFunction( - "_get_voltage", - [WebAPICommand("web_summary", "summary")], - ), str(DataOptions.FANS): DataFunction( "_get_fans", [WebAPICommand("web_summary", "summary")], @@ -82,6 +79,10 @@ EPIC_DATA_LOC = DataLocations( "_is_mining", [WebAPICommand("web_summary", "summary")], ), + str(DataOptions.POOLS): DataFunction( + "_get_pools", + [WebAPICommand("web_summary", "summary")], + ), } ) @@ -219,20 +220,6 @@ class ePIC(ePICFirmware): except KeyError: pass - async def _get_voltage(self, web_summary: dict = None) -> Optional[float]: - if web_summary is None: - try: - web_summary = await self.web.summary() - except APIError: - pass - - if web_summary is not None: - try: - voltage = web_summary["Power Supply Stats"]["Output Voltage"] - return voltage - except KeyError: - pass - async def _get_hashrate(self, web_summary: dict = None) -> Optional[float]: if web_summary is None: try: @@ -323,6 +310,20 @@ class ePIC(ePICFirmware): except APIError: pass + tuned = True + if web_summary is not None: + tuner_running = web_summary["PerpetualTune"]["Running"] + if tuner_running: + algo_info = web_summary["PerpetualTune"]["Algorithm"] + if algo_info.get("VoltageOptimizer") is not None: + tuned = algo_info["VoltageOptimizer"].get("Optimized") + elif algo_info.get("BoardTune") is not None: + tuned = algo_info["BoardTune"].get("Optimized") + else: + tuned = algo_info["ChipTune"].get("Optimized") + # To be extra detailed, also ensure the miner is in "Mining" state + tuned = tuned and web_summary["Status"]["Operating State"] == "Mining" + hb_list = [ HashBoard(slot=i, expected_chips=self.expected_chips) for i in range(self.expected_hashboards) @@ -349,6 +350,8 @@ class ePIC(ePICFirmware): ).into(self.algo.unit.default) hb_list[hb["Index"]].chips = num_of_chips hb_list[hb["Index"]].temp = hb["Temperature"] + hb_list[hb["Index"]].tuned = tuned + hb_list[hb["Index"]].voltage = hb["Input Voltage"] return hb_list async def _is_mining(self, web_summary, *args, **kwargs) -> Optional[bool]: @@ -411,3 +414,35 @@ class ePIC(ePICFirmware): except KeyError: pass return errors + + async def _get_pools(self, web_summary: dict = None) -> List[PoolMetrics]: + if web_summary is None: + try: + web_summary = await self.web.summary() + except APIError: + pass + + pool_data = [] + try: + if web_summary is not None: + if ( + web_summary.get("Session") is not None + and web_summary.get("Stratum") is not None + ): + pool_data.append( + PoolMetrics( + accepted=web_summary["Session"].get("Accepted"), + rejected=web_summary["Session"].get("Rejected"), + latency=web_summary["Stratum"].get("Average Latency"), + get_failures=0, + remote_failures=0, + active=web_summary["Stratum"].get("IsPoolConnected"), + alive=web_summary["Stratum"].get("IsPoolConnected"), + url=web_summary["Stratum"].get("Current Pool"), + user=web_summary["Stratum"].get("Current User"), + index=web_summary["Stratum"].get("Config Id"), + ) + ) + return pool_data + except LookupError: + pass diff --git a/pyasic/miners/data.py b/pyasic/miners/data.py index cc95a5cc..ad457de3 100644 --- a/pyasic/miners/data.py +++ b/pyasic/miners/data.py @@ -37,7 +37,6 @@ class DataOptions(Enum): IS_MINING = "is_mining" UPTIME = "uptime" CONFIG = "config" - VOLTAGE = "voltage" POOLS = "pools" def __str__(self):