From 86155db455dc0e038d5f0ac0d3451548e066e28b Mon Sep 17 00:00:00 2001 From: Colin Crossman Date: Fri, 4 Nov 2022 15:48:30 -0600 Subject: [PATCH 01/30] Initial modifications to account for differential hashboard counts Now storing the hasboard data as an array of datastructs. Not fully fleshed out yet, but this is where I'm going. --- pyasic/data/__init__.py | 35 ++++++++++++++++++++++++++++-- pyasic/miners/_backends/btminer.py | 23 +++++++++++++++++--- 2 files changed, 53 insertions(+), 5 deletions(-) diff --git a/pyasic/data/__init__.py b/pyasic/data/__init__.py index af2ac560..a18edb94 100644 --- a/pyasic/data/__init__.py +++ b/pyasic/data/__init__.py @@ -15,12 +15,23 @@ from typing import Union, List from dataclasses import dataclass, field, asdict from datetime import datetime, timezone +from functools import reduce import time import json import copy from .error_codes import X19Error, WhatsminerError, BraiinsOSError, InnosiliconError +@dataclass +class HashBoard: + slot: int = 0 + hashrate: float = 0.0 + temp: int = -1 + chip_temp: int = -1 + chips: int = 0 + expected_chips: int = 0 + missing: bool = True + @dataclass class MinerData: @@ -108,6 +119,10 @@ class MinerData: ] = field(default_factory=list) fault_light: Union[bool, None] = None efficiency: int = field(init=False) + hashboards: List[HashBoard] = field(default_factory=list) + ideal_hashboards: int = 1 + + def __post_init__(self): self.datetime = datetime.now(timezone.utc).astimezone() @@ -162,9 +177,13 @@ class MinerData: return cp @property - def total_chips(self): # noqa - Skip PyCharm inspection + def old_total_chips(self): # noqa - Skip PyCharm inspection return self.right_chips + self.center_chips + self.left_chips + @property + def total_chips(self): # noqa - Skip PyCharm inspection + return reduce(lambda x, y: x + y, [board.chips for board in self.hashboards]) + @total_chips.setter def total_chips(self, val): pass @@ -186,7 +205,7 @@ class MinerData: pass @property - def temperature_avg(self): # noqa - Skip PyCharm inspection + def old_temperature_avg(self): # noqa - Skip PyCharm inspection total_temp = 0 temp_count = 0 for temp in [ @@ -201,6 +220,18 @@ class MinerData: return 0 return round(total_temp / temp_count) + @property + def temperature_avg(self): # noqa - Skip PyCharm inspection + total_temp = 0 + temp_count = 0 + for temp in self.hashboards: + if temp.temp and not temp.temp == -1: + total_temp += temp.temp + temp_count += 1 + if not temp_count > 0: + return 0 + return round(total_temp / temp_count) + @temperature_avg.setter def temperature_avg(self, val): pass diff --git a/pyasic/miners/_backends/btminer.py b/pyasic/miners/_backends/btminer.py index e6d22d07..96e16174 100644 --- a/pyasic/miners/_backends/btminer.py +++ b/pyasic/miners/_backends/btminer.py @@ -21,7 +21,7 @@ from pyasic.API.btminer import BTMinerAPI from pyasic.miners.base import BaseMiner from pyasic.errors import APIError -from pyasic.data import MinerData +from pyasic.data import MinerData, HashBoard from pyasic.data.error_codes import WhatsminerError, MinerErrorData from pyasic.config import MinerConfig @@ -254,7 +254,7 @@ class BTMiner(BaseMiner): Returns: A [`MinerData`][pyasic.data.MinerData] instance containing the miners data. """ - data = MinerData(ip=str(self.ip), ideal_chips=self.nominal_chips * 3) + data = MinerData(ip=str(self.ip), ideal_chips=self.nominal_chips * self.ideal_hashboards) mac = None @@ -372,6 +372,23 @@ class BTMiner(BaseMiner): ) ) + + if devs: + dev_data = devs.get("DEVS") + if dev_data: + for board in dev_data: + temp_board = HashBoard( + slot = board["ASC"], + chip_temp = round(board["Chip Temp Avg"]), + temp = round(board["Temperature"]), + hashrate = round(board["MHS 1m"] / 1000000, 2), + chips = board["Effective Chips"], + missing = False if board["Effective Chips"] > 0 else True, + expected_chips = self.nominal_chips, + ) + data.hashboards.append(temp_board) + + """ if devs: temp_data = devs.get("DEVS") if temp_data: @@ -398,7 +415,7 @@ class BTMiner(BaseMiner): for board in boards: _id = board[id_key] - offset chips = board["Effective Chips"] - setattr(data, board_map[_id], chips) + setattr(data, board_map[_id], chips)""" if pools: pool_1 = None From d3cca11322c940b834d4090f08febda5cf2164ed Mon Sep 17 00:00:00 2001 From: Upstream Data Date: Fri, 4 Nov 2022 19:44:19 -0600 Subject: [PATCH 02/30] feature: add new `HashBoard` data structure to bmminer, and add `ideal_hashboards` to `BaseMiner`. --- pyasic/miners/_backends/bmminer.py | 69 ++++++++++++++---------------- pyasic/miners/base.py | 1 + 2 files changed, 32 insertions(+), 38 deletions(-) diff --git a/pyasic/miners/_backends/bmminer.py b/pyasic/miners/_backends/bmminer.py index d19e0732..8f645761 100644 --- a/pyasic/miners/_backends/bmminer.py +++ b/pyasic/miners/_backends/bmminer.py @@ -20,7 +20,7 @@ from typing import Union, List from pyasic.API.bmminer import BMMinerAPI from pyasic.miners.base import BaseMiner -from pyasic.data import MinerData +from pyasic.data import MinerData, HashBoard from pyasic.config import MinerConfig from pyasic.data.error_codes import MinerErrorData @@ -252,30 +252,37 @@ class BMMiner(BaseMiner): if board_offset == -1: board_offset = 1 - data.left_chips = boards[1].get(f"chain_acn{board_offset}") - data.center_chips = boards[1].get(f"chain_acn{board_offset+1}") - data.right_chips = boards[1].get(f"chain_acn{board_offset+2}") + env_temp_list = [] + for i in range(board_offset, board_offset + self.ideal_hashboards): + hashboard = HashBoard( + slot=i - board_offset, expected_chips=self.nominal_chips + ) - try: - data.left_board_hashrate = round( - float(boards[1].get(f"chain_rate{board_offset}")) / 1000, 2 - ) - except ValueError as e: - data.left_board_hashrate = round(0.00, 2) - try: - data.center_board_hashrate = round( - float(boards[1].get(f"chain_rate{board_offset+1}")) / 1000, - 2, - ) - except ValueError as e: - data.center_board_hashrate = round(0.00, 2) - try: - data.right_board_hashrate = round( - float(boards[1].get(f"chain_rate{board_offset+2}")) / 1000, - 2, - ) - except ValueError as e: - data.right_board_hashrate = round(0.00, 2) + chip_temp = boards[1].get(f"temp{i}") + if chip_temp: + hashboard.chip_temp = round(chip_temp) + + temp = boards[1].get(f"temp2_{i}") + if temp: + hashboard.temp = round(temp) + + hashrate = boards[1].get(f"chain_rate{i}") + if hashrate: + hashboard.hashrate = round(float(hashrate) / 1000, 2) + + chips = boards[1].get(f"chain_acn{i}") + if chips: + hashboard.chips = chips + hashboard.missing = False + if (not chips) or (not chips > 0): + hashboard.missing = True + data.hashboards.append(hashboard) + if f"temp_pcb{i}" in temp[1].keys(): + env_temp = temp[1][f"temp_pcb{i}"].split("-")[0] + if not env_temp == 0: + env_temp_list.append(int(env_temp)) + if not env_temp_list == []: + data.env_temp = sum(env_temp_list) / len(env_temp_list) if stats: temp = stats.get("STATS") @@ -293,20 +300,6 @@ class BMMiner(BaseMiner): data, f"fan_{fan + 1}", temp[1].get(f"fan{fan_offset+fan}") ) - board_map = {0: "left_board", 1: "center_board", 2: "right_board"} - env_temp_list = [] - for item in range(3): - board_temp = temp[1].get(f"temp{item + board_offset}") - chip_temp = temp[1].get(f"temp2_{item + board_offset}") - setattr(data, f"{board_map[item]}_chip_temp", chip_temp) - setattr(data, f"{board_map[item]}_temp", board_temp) - if f"temp_pcb{item}" in temp[1].keys(): - env_temp = temp[1][f"temp_pcb{item}"].split("-")[0] - if not env_temp == 0: - env_temp_list.append(int(env_temp)) - if not env_temp_list == []: - data.env_temp = sum(env_temp_list) / len(env_temp_list) - if pools: pool_1 = None pool_2 = None diff --git a/pyasic/miners/base.py b/pyasic/miners/base.py index fcdbe964..c945faaf 100644 --- a/pyasic/miners/base.py +++ b/pyasic/miners/base.py @@ -43,6 +43,7 @@ class BaseMiner(ABC): self.version = None self.fan_count = 2 self.config = None + self.ideal_hashboards = 3 def __new__(cls, *args, **kwargs): if cls is BaseMiner: From e96d9447d1e0ea422f003a52baa1f37f266e855a Mon Sep 17 00:00:00 2001 From: Upstream Data Date: Fri, 4 Nov 2022 19:44:49 -0600 Subject: [PATCH 03/30] format: reformat btminer.py --- pyasic/miners/_backends/btminer.py | 98 +++++++++++++----------------- 1 file changed, 42 insertions(+), 56 deletions(-) diff --git a/pyasic/miners/_backends/btminer.py b/pyasic/miners/_backends/btminer.py index 96e16174..a5716b22 100644 --- a/pyasic/miners/_backends/btminer.py +++ b/pyasic/miners/_backends/btminer.py @@ -166,17 +166,9 @@ class BTMiner(BaseMiner): for err in err_data["Msg"]["error_code"]: if isinstance(err, dict): for code in err: - data.append( - WhatsminerError( - error_code=int(code) - ) - ) + data.append(WhatsminerError(error_code=int(code))) else: - data.append( - WhatsminerError( - error_code=int(err) - ) - ) + data.append(WhatsminerError(error_code=int(err))) except APIError: summary_data = await self.api.summary() if summary_data[0].get("Error Code Count"): @@ -254,7 +246,9 @@ class BTMiner(BaseMiner): Returns: A [`MinerData`][pyasic.data.MinerData] instance containing the miners data. """ - data = MinerData(ip=str(self.ip), ideal_chips=self.nominal_chips * self.ideal_hashboards) + data = MinerData( + ip=str(self.ip), ideal_chips=self.nominal_chips * self.ideal_hashboards + ) mac = None @@ -361,61 +355,53 @@ class BTMiner(BaseMiner): if isinstance(err, dict): for code in err: data.errors.append( - WhatsminerError( - error_code=int(code) - ) + WhatsminerError(error_code=int(code)) ) else: - data.errors.append( - WhatsminerError( - error_code=int(err) - ) - ) + data.errors.append(WhatsminerError(error_code=int(err))) - if devs: dev_data = devs.get("DEVS") if dev_data: for board in dev_data: temp_board = HashBoard( - slot = board["ASC"], - chip_temp = round(board["Chip Temp Avg"]), - temp = round(board["Temperature"]), - hashrate = round(board["MHS 1m"] / 1000000, 2), - chips = board["Effective Chips"], - missing = False if board["Effective Chips"] > 0 else True, - expected_chips = self.nominal_chips, - ) + slot=board["ASC"], + chip_temp=round(board["Chip Temp Avg"]), + temp=round(board["Temperature"]), + hashrate=round(board["MHS 1m"] / 1000000, 2), + chips=board["Effective Chips"], + missing=False if board["Effective Chips"] > 0 else True, + expected_chips=self.nominal_chips, + ) data.hashboards.append(temp_board) - """ - if devs: - temp_data = devs.get("DEVS") - if temp_data: - board_map = {0: "left_board", 1: "center_board", 2: "right_board"} - for board in temp_data: - _id = board["ASC"] - chip_temp = round(board["Chip Temp Avg"]) - board_temp = round(board["Temperature"]) - hashrate = round(board["MHS 1m"] / 1000000, 2) - setattr(data, f"{board_map[_id]}_chip_temp", chip_temp) - setattr(data, f"{board_map[_id]}_temp", board_temp) - setattr(data, f"{board_map[_id]}_hashrate", hashrate) - - if devs: - boards = devs.get("DEVS") - if boards: - if len(boards) > 0: - board_map = {0: "left_chips", 1: "center_chips", 2: "right_chips"} - if "ID" in boards[0].keys(): - id_key = "ID" - else: - id_key = "ASC" - offset = boards[0][id_key] - for board in boards: - _id = board[id_key] - offset - chips = board["Effective Chips"] - setattr(data, board_map[_id], chips)""" + # if devs: + # temp_data = devs.get("DEVS") + # if temp_data: + # board_map = {0: "left_board", 1: "center_board", 2: "right_board"} + # for board in temp_data: + # _id = board["ASC"] + # chip_temp = round(board["Chip Temp Avg"]) + # board_temp = round(board["Temperature"]) + # hashrate = round(board["MHS 1m"] / 1000000, 2) + # setattr(data, f"{board_map[_id]}_chip_temp", chip_temp) + # setattr(data, f"{board_map[_id]}_temp", board_temp) + # setattr(data, f"{board_map[_id]}_hashrate", hashrate) + # + # if devs: + # boards = devs.get("DEVS") + # if boards: + # if len(boards) > 0: + # board_map = {0: "left_chips", 1: "center_chips", 2: "right_chips"} + # if "ID" in boards[0].keys(): + # id_key = "ID" + # else: + # id_key = "ASC" + # offset = boards[0][id_key] + # for board in boards: + # _id = board[id_key] - offset + # chips = board["Effective Chips"] + # setattr(data, board_map[_id], chips) if pools: pool_1 = None From 6eb9cdce90344163dddf883cfcabf2ca3658c4c1 Mon Sep 17 00:00:00 2001 From: Upstream Data Date: Fri, 4 Nov 2022 19:55:13 -0600 Subject: [PATCH 04/30] feature: add `left_chips`, `center_chips`, and `right_chips` to `MinerData` as properties that compute the correct board position from hashboards. --- pyasic/data/__init__.py | 68 +++++++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 27 deletions(-) diff --git a/pyasic/data/__init__.py b/pyasic/data/__init__.py index a18edb94..0ec05a53 100644 --- a/pyasic/data/__init__.py +++ b/pyasic/data/__init__.py @@ -102,9 +102,9 @@ class MinerData: fan_3: int = -1 fan_4: int = -1 fan_psu: int = -1 - left_chips: int = 0 - center_chips: int = 0 - right_chips: int = 0 + left_chips: int = field(init=False) + center_chips: int = field(init=False) + right_chips: int = field(init=False) total_chips: int = field(init=False) ideal_chips: int = 1 percent_ideal: float = field(init=False) @@ -176,18 +176,48 @@ class MinerData: setattr(cp, key, item & other_item) return cp - @property - def old_total_chips(self): # noqa - Skip PyCharm inspection - return self.right_chips + self.center_chips + self.left_chips - @property def total_chips(self): # noqa - Skip PyCharm inspection - return reduce(lambda x, y: x + y, [board.chips for board in self.hashboards]) + return reduce(lambda x, y: x + y, [hb.chips for hb in self.hashboards]) @total_chips.setter def total_chips(self, val): pass + @property + def left_chips(self): # noqa - Skip PyCharm inspection + if len(self.hashboards) in [2, 3]: + return self.hashboards[0].chips + return 0 + + @left_chips.setter + def left_chips(self, val): + pass + + @property + def center_chips(self): # noqa - Skip PyCharm inspection + if len(self.hashboards) == 1: + return self.hashboards[0].chips + if len(self.hashboards) == 3: + return self.hashboards[1].chips + return 0 + + @center_chips.setter + def center_chips(self, val): + pass + + @property + def right_chips(self): # noqa - Skip PyCharm inspection + if len(self.hashboards) == 2: + return self.hashboards[1].chips + if len(self.hashboards) == 3: + return self.hashboards[2].chips + return 0 + + @right_chips.setter + def right_chips(self, val): + pass + @property def nominal(self): # noqa - Skip PyCharm inspection return self.ideal_chips == self.total_chips @@ -204,29 +234,13 @@ class MinerData: def percent_ideal(self, val): pass - @property - def old_temperature_avg(self): # noqa - Skip PyCharm inspection - total_temp = 0 - temp_count = 0 - for temp in [ - self.left_board_chip_temp, - self.center_board_chip_temp, - self.right_board_chip_temp, - ]: - if temp and not temp == -1: - total_temp += temp - temp_count += 1 - if not temp_count > 0: - return 0 - return round(total_temp / temp_count) - @property def temperature_avg(self): # noqa - Skip PyCharm inspection total_temp = 0 temp_count = 0 - for temp in self.hashboards: - if temp.temp and not temp.temp == -1: - total_temp += temp.temp + for hb in self.hashboards: + if hb.temp and not hb.temp == -1: + total_temp += hb.temp temp_count += 1 if not temp_count > 0: return 0 From 6c2e0f59b1c5181dcca4e0b9f75ce5b79a5a0dc5 Mon Sep 17 00:00:00 2001 From: Upstream Data Date: Fri, 4 Nov 2022 20:00:03 -0600 Subject: [PATCH 05/30] feature: add the remainder of the backwards compatible `MinerData` board related parts that were lost in converting to `HashBoard` dataclass. --- pyasic/data/__init__.py | 124 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 112 insertions(+), 12 deletions(-) diff --git a/pyasic/data/__init__.py b/pyasic/data/__init__.py index 0ec05a53..2cf5f583 100644 --- a/pyasic/data/__init__.py +++ b/pyasic/data/__init__.py @@ -84,17 +84,19 @@ class MinerData: model: str = "Unknown" hostname: str = "Unknown" hashrate: float = 0 - left_board_hashrate: float = 0.0 - center_board_hashrate: float = 0.0 - right_board_hashrate: float = 0.0 + hashboards: List[HashBoard] = field(default_factory=list) + ideal_hashboards: int = 1 + left_board_hashrate: float = field(init=False) + center_board_hashrate: float = field(init=False) + right_board_hashrate: float = field(init=False) temperature_avg: int = field(init=False) env_temp: float = -1.0 - left_board_temp: int = -1 - left_board_chip_temp: int = -1 - center_board_temp: int = -1 - center_board_chip_temp: int = -1 - right_board_temp: int = -1 - right_board_chip_temp: int = -1 + left_board_temp: int = field(init=False) + left_board_chip_temp: int = field(init=False) + center_board_temp: int = field(init=False) + center_board_chip_temp: int = field(init=False) + right_board_temp: int = field(init=False) + right_board_chip_temp: int = field(init=False) wattage: int = -1 wattage_limit: int = -1 fan_1: int = -1 @@ -119,9 +121,6 @@ class MinerData: ] = field(default_factory=list) fault_light: Union[bool, None] = None efficiency: int = field(init=False) - hashboards: List[HashBoard] = field(default_factory=list) - ideal_hashboards: int = 1 - def __post_init__(self): @@ -218,6 +217,107 @@ class MinerData: def right_chips(self, val): pass + @property + def left_board_hashrate(self): # noqa - Skip PyCharm inspection + if len(self.hashboards) in [2, 3]: + return self.hashboards[0].hashrate + return 0 + + @left_board_hashrate.setter + def left_board_hashrate(self, val): + pass + + @property + def center_board_hashrate(self): # noqa - Skip PyCharm inspection + if len(self.hashboards) == 1: + return self.hashboards[0].hashrate + if len(self.hashboards) == 3: + return self.hashboards[1].hashrate + return 0 + + @center_board_hashrate.setter + def center_board_hashrate(self, val): + pass + + @property + def right_board_hashrate(self): # noqa - Skip PyCharm inspection + if len(self.hashboards) == 2: + return self.hashboards[1].hashrate + if len(self.hashboards) == 3: + return self.hashboards[2].hashrate + return 0 + + @right_board_hashrate.setter + def right_board_hashrate(self, val): + pass + + @property + def left_board_temp(self): # noqa - Skip PyCharm inspection + if len(self.hashboards) in [2, 3]: + return self.hashboards[0].temp + return 0 + + @left_board_temp.setter + def left_board_temp(self, val): + pass + + @property + def center_board_temp(self): # noqa - Skip PyCharm inspection + if len(self.hashboards) == 1: + return self.hashboards[0].temp + if len(self.hashboards) == 3: + return self.hashboards[1].temp + return 0 + + @center_board_temp.setter + def center_board_temp(self, val): + pass + + @property + def right_board_temp(self): # noqa - Skip PyCharm inspection + if len(self.hashboards) == 2: + return self.hashboards[1].temp + if len(self.hashboards) == 3: + return self.hashboards[2].temp + return 0 + + @right_board_temp.setter + def right_board_temp(self, val): + pass + @property + def left_board_chip_temp(self): # noqa - Skip PyCharm inspection + if len(self.hashboards) in [2, 3]: + return self.hashboards[0].chip_temp + return 0 + + @left_board_chip_temp.setter + def left_board_chip_temp(self, val): + pass + + @property + def center_board_chip_temp(self): # noqa - Skip PyCharm inspection + if len(self.hashboards) == 1: + return self.hashboards[0].chip_temp + if len(self.hashboards) == 3: + return self.hashboards[1].chip_temp + return 0 + + @center_board_chip_temp.setter + def center_board_chip_temp(self, val): + pass + + @property + def right_board_chip_temp(self): # noqa - Skip PyCharm inspection + if len(self.hashboards) == 2: + return self.hashboards[1].chip_temp + if len(self.hashboards) == 3: + return self.hashboards[2].chip_temp + return 0 + + @right_board_chip_temp.setter + def right_board_chip_temp(self, val): + pass + @property def nominal(self): # noqa - Skip PyCharm inspection return self.ideal_chips == self.total_chips From 37ebb9e6c3b9b441f4dbcc43be79cdc1a5308b4d Mon Sep 17 00:00:00 2001 From: Upstream Data Date: Fri, 4 Nov 2022 20:10:50 -0600 Subject: [PATCH 06/30] feature: add T9 support for new `HashBoard` format. --- pyasic/miners/antminer/hiveon/X9/T9.py | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/pyasic/miners/antminer/hiveon/X9/T9.py b/pyasic/miners/antminer/hiveon/X9/T9.py index 4d0a13e8..5cb97031 100644 --- a/pyasic/miners/antminer/hiveon/X9/T9.py +++ b/pyasic/miners/antminer/hiveon/X9/T9.py @@ -15,7 +15,7 @@ from pyasic.miners._backends import Hiveon # noqa - Ignore access to _module from pyasic.miners._types import T9 # noqa - Ignore access to _module -from pyasic.data import MinerData +from pyasic.data import MinerData, HashBoard from pyasic.settings import PyasicSettings @@ -97,14 +97,15 @@ class HiveonT9(Hiveon, T9): ) board_map = { - "left": [2, 9, 10], - "center": [3, 11, 12], - "right": [4, 13, 14], + 0: [2, 9, 10], + 1: [3, 11, 12], + 2: [4, 13, 14], } env_temp_list = [] for board in board_map.keys(): + hashboard = HashBoard(slot=board, expected_chips=self.nominal_chips) chips = 0 hashrate = 0 chip_temp = 0 @@ -121,10 +122,16 @@ class HiveonT9(Hiveon, T9): hashrate += boards[1][f"chain_rate{chipset}"] chips += boards[1][f"chain_acn{chipset}"] - setattr(data, f"{board}_chips", chips) - setattr(data, f"{board}_board_hashrate", hashrate) - setattr(data, f"{board}_board_temp", board_temp) - setattr(data, f"{board}_board_chip_temp", chip_temp) + hashboard.hashrate = hashrate + hashboard.chips = chips + hashboard.temp = board_temp + hashboard.chip_temp = chip_temp + if not chips == 0: + hashboard.missing = False + else: + hashboard.missing = True + data.hashboards.append(hashboard) + if not env_temp_list == []: data.env_temp = sum(env_temp_list) / len(env_temp_list) From 310844304157f10559c4801c08151d5dac86ef03 Mon Sep 17 00:00:00 2001 From: Upstream Data Date: Fri, 4 Nov 2022 20:22:07 -0600 Subject: [PATCH 07/30] feature: add bosminer support for new `HashBoard` format. --- pyasic/miners/_backends/bosminer.py | 31 +++++++++++++++++------------ 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/pyasic/miners/_backends/bosminer.py b/pyasic/miners/_backends/bosminer.py index 73eca848..dcd70c10 100644 --- a/pyasic/miners/_backends/bosminer.py +++ b/pyasic/miners/_backends/bosminer.py @@ -25,7 +25,7 @@ from pyasic.API.bosminer import BOSMinerAPI from pyasic.errors import APIError from pyasic.data.error_codes import BraiinsOSError, MinerErrorData -from pyasic.data import MinerData +from pyasic.data import MinerData, HashBoard from pyasic.config import MinerConfig @@ -300,7 +300,14 @@ class BOSMiner(BaseMiner): Returns: A [`MinerData`][pyasic.data.MinerData] instance containing the miners data. """ - data = MinerData(ip=str(self.ip), ideal_chips=self.nominal_chips * 3) + data = MinerData( + ip=str(self.ip), + ideal_chips=self.nominal_chips * 3, + hashboards=[ + HashBoard(slot=i, expected_chips=self.nominal_chips) + for i in range(self.ideal_hashboards) + ], + ) board_offset = -1 fan_offset = -1 @@ -361,14 +368,13 @@ class BOSMiner(BaseMiner): temp = temps[0].get("TEMPS") if temp: if len(temp) > 0: - board_map = {0: "left_board", 1: "center_board", 2: "right_board"} offset = 6 if temp[0]["ID"] in [6, 7, 8] else temp[0]["ID"] for board in temp: _id = board["ID"] - offset chip_temp = round(board["Chip"]) board_temp = round(board["Board"]) - setattr(data, f"{board_map[_id]}_chip_temp", chip_temp) - setattr(data, f"{board_map[_id]}_temp", board_temp) + data.hashboards[_id].chip_temp = chip_temp + data.hashboards[_id].temp = board_temp if fans: fan_data = fans[0].get("FANS") @@ -461,27 +467,26 @@ class BOSMiner(BaseMiner): boards = devdetails[0].get("DEVDETAILS") if boards: if len(boards) > 0: - board_map = {0: "left_chips", 1: "center_chips", 2: "right_chips"} offset = 6 if boards[0]["ID"] in [6, 7, 8] else boards[0]["ID"] for board in boards: _id = board["ID"] - offset chips = board["Chips"] - setattr(data, board_map[_id], chips) + data.hashboards[_id].chips = chips + if chips > 0: + data.hashboards[_id].missing = False + else: + data.hashboards[_id].missing = True + if devs: boards = devs[0].get("DEVS") if boards: if len(boards) > 0: - board_map = { - 0: "left_board_hashrate", - 1: "center_board_hashrate", - 2: "right_board_hashrate", - } offset = 6 if boards[0]["ID"] in [6, 7, 8] else boards[0]["ID"] for board in boards: _id = board["ID"] - offset hashrate = round(board["MHS 1m"] / 1000000, 2) - setattr(data, board_map[_id], hashrate) + data.hashboards[_id].hashrate = hashrate return data async def get_mac(self): From 6da9b580889239405058a466e2a0dfbe9d5e0eaa Mon Sep 17 00:00:00 2001 From: Upstream Data Date: Fri, 4 Nov 2022 20:26:28 -0600 Subject: [PATCH 08/30] bug: fix missing initialization variables on HashBoard when being called from within `get_data` on bos, T9, and btminer. --- pyasic/miners/_backends/bmminer.py | 6 +++++- pyasic/miners/_backends/bosminer.py | 3 ++- pyasic/miners/_backends/btminer.py | 2 +- pyasic/miners/antminer/hiveon/X9/T9.py | 10 ++++++++-- 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/pyasic/miners/_backends/bmminer.py b/pyasic/miners/_backends/bmminer.py index 8f645761..469dd671 100644 --- a/pyasic/miners/_backends/bmminer.py +++ b/pyasic/miners/_backends/bmminer.py @@ -191,7 +191,11 @@ class BMMiner(BaseMiner): Returns: A [`MinerData`][pyasic.data.MinerData] instance containing the miners data. """ - data = MinerData(ip=str(self.ip), ideal_chips=self.nominal_chips * 3) + data = MinerData( + ip=str(self.ip), + ideal_chips=self.nominal_chips * self.ideal_hashboards, + ideal_hashboards=self.ideal_hashboards, + ) board_offset = -1 fan_offset = -1 diff --git a/pyasic/miners/_backends/bosminer.py b/pyasic/miners/_backends/bosminer.py index dcd70c10..1ec0af66 100644 --- a/pyasic/miners/_backends/bosminer.py +++ b/pyasic/miners/_backends/bosminer.py @@ -302,7 +302,8 @@ class BOSMiner(BaseMiner): """ data = MinerData( ip=str(self.ip), - ideal_chips=self.nominal_chips * 3, + ideal_chips=self.nominal_chips * self.ideal_hashboards, + ideal_hashboards=self.ideal_hashboards, hashboards=[ HashBoard(slot=i, expected_chips=self.nominal_chips) for i in range(self.ideal_hashboards) diff --git a/pyasic/miners/_backends/btminer.py b/pyasic/miners/_backends/btminer.py index a5716b22..41ff37b5 100644 --- a/pyasic/miners/_backends/btminer.py +++ b/pyasic/miners/_backends/btminer.py @@ -247,7 +247,7 @@ class BTMiner(BaseMiner): A [`MinerData`][pyasic.data.MinerData] instance containing the miners data. """ data = MinerData( - ip=str(self.ip), ideal_chips=self.nominal_chips * self.ideal_hashboards + ip=str(self.ip), ideal_chips=self.nominal_chips * self.ideal_hashboards, ideal_hashboards=self.ideal_hashboards, ) mac = None diff --git a/pyasic/miners/antminer/hiveon/X9/T9.py b/pyasic/miners/antminer/hiveon/X9/T9.py index 5cb97031..44fb209b 100644 --- a/pyasic/miners/antminer/hiveon/X9/T9.py +++ b/pyasic/miners/antminer/hiveon/X9/T9.py @@ -39,7 +39,11 @@ class HiveonT9(Hiveon, T9): Returns: A [`MinerData`][pyasic.data.MinerData] instance containing the miners data. """ - data = MinerData(ip=str(self.ip), ideal_chips=self.nominal_chips * 3) + data = MinerData( + ip=str(self.ip), + ideal_chips=self.nominal_chips * self.ideal_hashboards, + ideal_hashboards=self.ideal_hashboards, + ) board_offset = -1 fan_offset = -1 @@ -105,7 +109,9 @@ class HiveonT9(Hiveon, T9): env_temp_list = [] for board in board_map.keys(): - hashboard = HashBoard(slot=board, expected_chips=self.nominal_chips) + hashboard = HashBoard( + slot=board, expected_chips=self.nominal_chips + ) chips = 0 hashrate = 0 chip_temp = 0 From e431a06ac5eaf1000293b4ba770b3cabfc263793 Mon Sep 17 00:00:00 2001 From: Colin Crossman Date: Fri, 4 Nov 2022 21:28:07 -0600 Subject: [PATCH 09/30] feature: add cgminer support for new `HashBoard` structure --- pyasic/miners/_backends/cgminer.py | 61 +++++++++++++++++------------- 1 file changed, 34 insertions(+), 27 deletions(-) diff --git a/pyasic/miners/_backends/cgminer.py b/pyasic/miners/_backends/cgminer.py index 99c05e9c..0cade4d5 100644 --- a/pyasic/miners/_backends/cgminer.py +++ b/pyasic/miners/_backends/cgminer.py @@ -22,7 +22,7 @@ from pyasic.miners.base import BaseMiner from pyasic.errors import APIError from pyasic.config import MinerConfig -from pyasic.data import MinerData +from pyasic.data import MinerData, HashBoard from pyasic.data.error_codes import MinerErrorData from pyasic.settings import PyasicSettings @@ -179,7 +179,9 @@ class CGMiner(BaseMiner): Returns: A [`MinerData`][pyasic.data.MinerData] instance containing the miners data. """ - data = MinerData(ip=str(self.ip), ideal_chips=self.nominal_chips * 3) + data = MinerData(ip=str(self.ip), ideal_chips=self.nominal_chips * self.ideal_hashboards, ideal_hashboards=self.ideal_hashboards, + ) + board_offset = -1 fan_offset = -1 @@ -235,19 +237,37 @@ class CGMiner(BaseMiner): if board_offset == -1: board_offset = 1 - data.left_chips = boards[1].get(f"chain_acn{board_offset}") - data.center_chips = boards[1].get(f"chain_acn{board_offset+1}") - data.right_chips = boards[1].get(f"chain_acn{board_offset+2}") + env_temp_list = [] + for i in range(board_offset, board_offset + self.ideal_hashboards): + hashboard = HashBoard( + slot=i - board_offset, expected_chips=self.nominal_chips + ) - data.left_board_hashrate = round( - float(boards[1].get(f"chain_rate{board_offset}")) / 1000, 2 - ) - data.center_board_hashrate = round( - float(boards[1].get(f"chain_rate{board_offset+1}")) / 1000, 2 - ) - data.right_board_hashrate = round( - float(boards[1].get(f"chain_rate{board_offset+2}")) / 1000, 2 - ) + chip_temp = boards[1].get(f"temp{i}") + if chip_temp: + hashboard.chip_temp = round(chip_temp) + + temp = boards[1].get(f"temp2_{i}") + if temp: + hashboard.temp = round(temp) + + hashrate = boards[1].get(f"chain_rate{i}") + if hashrate: + hashboard.hashrate = round(float(hashrate) / 1000, 2) + + chips = boards[1].get(f"chain_acn{i}") + if chips: + hashboard.chips = chips + hashboard.missing = False + if (not chips) or (not chips > 0): + hashboard.missing = True + data.hashboards.append(hashboard) + if f"temp_pcb{i}" in temp[1].keys(): + env_temp = temp[1][f"temp_pcb{i}"].split("-")[0] + if not env_temp == 0: + env_temp_list.append(int(env_temp)) + if not env_temp_list == []: + data.env_temp = sum(env_temp_list) / len(env_temp_list) if stats: temp = stats.get("STATS") @@ -265,19 +285,6 @@ class CGMiner(BaseMiner): data, f"fan_{fan + 1}", temp[1].get(f"fan{fan_offset+fan}") ) - board_map = {0: "left_board", 1: "center_board", 2: "right_board"} - env_temp_list = [] - for item in range(3): - board_temp = temp[1].get(f"temp{item + board_offset}") - chip_temp = temp[1].get(f"temp2_{item + board_offset}") - setattr(data, f"{board_map[item]}_chip_temp", chip_temp) - setattr(data, f"{board_map[item]}_temp", board_temp) - if f"temp_pcb{item}" in temp[1].keys(): - env_temp = temp[1][f"temp_pcb{item}"].split("-")[0] - if not env_temp == 0: - env_temp_list.append(int(env_temp)) - data.env_temp = sum(env_temp_list) / len(env_temp_list) - if pools: pool_1 = None pool_2 = None From 1970f8c9241ebd5680017865b92e373030a59932 Mon Sep 17 00:00:00 2001 From: Colin Crossman Date: Fri, 4 Nov 2022 21:28:33 -0600 Subject: [PATCH 10/30] feature: add innosilicon support for new `HashBoard` format. --- .../innosilicon/cgminer/T3X/T3H_Plus.py | 40 ++++++++----------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/pyasic/miners/innosilicon/cgminer/T3X/T3H_Plus.py b/pyasic/miners/innosilicon/cgminer/T3X/T3H_Plus.py index 581a0060..13283d7b 100644 --- a/pyasic/miners/innosilicon/cgminer/T3X/T3H_Plus.py +++ b/pyasic/miners/innosilicon/cgminer/T3X/T3H_Plus.py @@ -17,7 +17,7 @@ from pyasic.miners._types import InnosiliconT3HPlus # noqa - Ignore access to _ from pyasic.data import MinerData from pyasic.data.error_codes import InnosiliconError, MinerErrorData from pyasic.settings import PyasicSettings -from pyasic.config import MinerConfig +from pyasic.config import MinerConfig, HashBoard from pyasic.errors import APIError import httpx @@ -158,7 +158,11 @@ class CGMinerInnosiliconT3HPlus(CGMiner, InnosiliconT3HPlus): return errors async def get_data(self) -> MinerData: - data = MinerData(ip=str(self.ip), ideal_chips=self.nominal_chips * 3) + data = MinerData( + ip=str(self.ip), + ideal_chips=self.nominal_chips * self.ideal_hashboards, + ideal_hashboards=self.ideal_hashboards, + ) board_offset = -1 fan_offset = -1 @@ -215,32 +219,22 @@ class CGMinerInnosiliconT3HPlus(CGMiner, InnosiliconT3HPlus): if stats: stats = stats[0] if stats.get("STATS"): - board_map = {0: "left", 1: "center", 2: "right"} for idx, board in enumerate(stats["STATS"]): - chips = board.get("Num active chips") - if chips: - setattr(data, f"{board_map[idx]}_chips", chips) - temp = board.get("Temp") - if temp: - setattr(data, f"{board_map[idx]}_board_chip_temp", temp) + temp_board = HashBoard( + slot=idx, + chip_temp=round(board.get("Temp")), + chips=board.get("Num active chips"), + missing=False if board.get("Num active chips") > 0 else True, + expected_chips=self.nominal_chips, + ) + data.hashboards.append(temp_board) if all_data: if all_data.get("chain"): - board_map = {0: "left", 1: "center", 2: "right"} for idx, board in enumerate(all_data["chain"]): - temp = board.get("Temp max") - if temp: - setattr(data, f"{board_map[idx]}_board_chip_temp", temp) - temp_board = board.get("Temp min") - if temp_board: - setattr(data, f"{board_map[idx]}_board_temp", temp_board) - hr = board.get("Hash Rate H") - if hr: - setattr( - data, - f"{board_map[idx]}_board_hashrate", - round(hr / 1000000000000, 2), - ) + data.hashboards[idx].temp = round(board.get("Temp min")) + data.hashboards[idx].hashrate = round(board.get("Hash Rate H") / 1000000000000, 2) + if all_data.get("fansSpeed"): speed = round((all_data["fansSpeed"] * 6000) / 100) for fan in range(self.fan_count): From 104b4c18c2ed0812bd740645534593a4259840f3 Mon Sep 17 00:00:00 2001 From: Colin Crossman Date: Fri, 4 Nov 2022 21:28:59 -0600 Subject: [PATCH 11/30] format: remove vestigial elements of btminer --- pyasic/miners/_backends/btminer.py | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/pyasic/miners/_backends/btminer.py b/pyasic/miners/_backends/btminer.py index 41ff37b5..495fd9c8 100644 --- a/pyasic/miners/_backends/btminer.py +++ b/pyasic/miners/_backends/btminer.py @@ -375,34 +375,6 @@ class BTMiner(BaseMiner): ) data.hashboards.append(temp_board) - # if devs: - # temp_data = devs.get("DEVS") - # if temp_data: - # board_map = {0: "left_board", 1: "center_board", 2: "right_board"} - # for board in temp_data: - # _id = board["ASC"] - # chip_temp = round(board["Chip Temp Avg"]) - # board_temp = round(board["Temperature"]) - # hashrate = round(board["MHS 1m"] / 1000000, 2) - # setattr(data, f"{board_map[_id]}_chip_temp", chip_temp) - # setattr(data, f"{board_map[_id]}_temp", board_temp) - # setattr(data, f"{board_map[_id]}_hashrate", hashrate) - # - # if devs: - # boards = devs.get("DEVS") - # if boards: - # if len(boards) > 0: - # board_map = {0: "left_chips", 1: "center_chips", 2: "right_chips"} - # if "ID" in boards[0].keys(): - # id_key = "ID" - # else: - # id_key = "ASC" - # offset = boards[0][id_key] - # for board in boards: - # _id = board[id_key] - offset - # chips = board["Effective Chips"] - # setattr(data, board_map[_id], chips) - if pools: pool_1 = None pool_2 = None From e02457f0b265055d8a72a6a1c03e4a6723ff3918 Mon Sep 17 00:00:00 2001 From: Colin Crossman Date: Fri, 4 Nov 2022 21:55:44 -0600 Subject: [PATCH 12/30] bug: fix import for HashBoard --- pyasic/miners/innosilicon/cgminer/T3X/T3H_Plus.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyasic/miners/innosilicon/cgminer/T3X/T3H_Plus.py b/pyasic/miners/innosilicon/cgminer/T3X/T3H_Plus.py index 13283d7b..80571700 100644 --- a/pyasic/miners/innosilicon/cgminer/T3X/T3H_Plus.py +++ b/pyasic/miners/innosilicon/cgminer/T3X/T3H_Plus.py @@ -14,10 +14,10 @@ from pyasic.miners._backends import CGMiner # noqa - Ignore access to _module from pyasic.miners._types import InnosiliconT3HPlus # noqa - Ignore access to _module -from pyasic.data import MinerData +from pyasic.data import MinerData, HashBoard from pyasic.data.error_codes import InnosiliconError, MinerErrorData from pyasic.settings import PyasicSettings -from pyasic.config import MinerConfig, HashBoard +from pyasic.config import MinerConfig from pyasic.errors import APIError import httpx From d9b522734ad0c08db85d1f2bb4254870bc1b7ec9 Mon Sep 17 00:00:00 2001 From: Upstream Data Date: Sat, 5 Nov 2022 09:40:56 -0600 Subject: [PATCH 13/30] format: reformat T3H+ `get_data` to improve error handling and checking of data. --- .../innosilicon/cgminer/T3X/T3H_Plus.py | 33 +++++++++++++------ 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/pyasic/miners/innosilicon/cgminer/T3X/T3H_Plus.py b/pyasic/miners/innosilicon/cgminer/T3X/T3H_Plus.py index 80571700..50340daa 100644 --- a/pyasic/miners/innosilicon/cgminer/T3X/T3H_Plus.py +++ b/pyasic/miners/innosilicon/cgminer/T3X/T3H_Plus.py @@ -162,6 +162,10 @@ class CGMinerInnosiliconT3HPlus(CGMiner, InnosiliconT3HPlus): ip=str(self.ip), ideal_chips=self.nominal_chips * self.ideal_hashboards, ideal_hashboards=self.ideal_hashboards, + hashboards=[ + HashBoard(slot=i, expected_chips=self.nominal_chips) + for i in range(self.ideal_hashboards) + ], ) board_offset = -1 @@ -220,20 +224,29 @@ class CGMinerInnosiliconT3HPlus(CGMiner, InnosiliconT3HPlus): stats = stats[0] if stats.get("STATS"): for idx, board in enumerate(stats["STATS"]): - temp_board = HashBoard( - slot=idx, - chip_temp=round(board.get("Temp")), - chips=board.get("Num active chips"), - missing=False if board.get("Num active chips") > 0 else True, - expected_chips=self.nominal_chips, - ) - data.hashboards.append(temp_board) + data.hashboards[idx].missing = True + chips = board.get("Num active chips") + if chips: + data.hashboards[idx].chips = chips + if chips > 0: + data.hashboards[idx].missing = False if all_data: if all_data.get("chain"): for idx, board in enumerate(all_data["chain"]): - data.hashboards[idx].temp = round(board.get("Temp min")) - data.hashboards[idx].hashrate = round(board.get("Hash Rate H") / 1000000000000, 2) + temp = board.get("Temp min") + if temp: + data.hashboards[idx].temp = round(temp) + + hashrate = board.get("Hash Rate H") + if hashrate: + data.hashboards[idx].hashrate = round( + hashrate / 1000000000000, 2 + ) + + chip_temp = board.get("Temp max") + if chip_temp: + data.hashboards[idx].chip_temp = round(chip_temp) if all_data.get("fansSpeed"): speed = round((all_data["fansSpeed"] * 6000) / 100) From 92db8c8161bb27623d398f90f6ac5bc64418c8e4 Mon Sep 17 00:00:00 2001 From: Upstream Data Date: Sat, 5 Nov 2022 09:44:38 -0600 Subject: [PATCH 14/30] format: Improve T9 formatting with get data on hiveon. --- pyasic/miners/antminer/hiveon/X9/T9.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pyasic/miners/antminer/hiveon/X9/T9.py b/pyasic/miners/antminer/hiveon/X9/T9.py index 44fb209b..f2cd256e 100644 --- a/pyasic/miners/antminer/hiveon/X9/T9.py +++ b/pyasic/miners/antminer/hiveon/X9/T9.py @@ -132,10 +132,9 @@ class HiveonT9(Hiveon, T9): hashboard.chips = chips hashboard.temp = board_temp hashboard.chip_temp = chip_temp - if not chips == 0: + hashboard.missing = True + if chips and chips > 0: hashboard.missing = False - else: - hashboard.missing = True data.hashboards.append(hashboard) if not env_temp_list == []: From 23ebe460a4a9d21ef190db18d21c7ba61c5bd8a5 Mon Sep 17 00:00:00 2001 From: Upstream Data Date: Sat, 5 Nov 2022 09:47:25 -0600 Subject: [PATCH 15/30] format: Reformat some files. --- pyasic/data/__init__.py | 3 ++- pyasic/miners/_backends/bosminer.py | 1 - pyasic/miners/_backends/btminer.py | 4 +++- pyasic/miners/_backends/cgminer.py | 6 ++++-- pyasic/miners/_types/whatsminer/__init__.py | 2 +- pyasic/miners/whatsminer/btminer/M5X/__init__.py | 2 +- pyasic/miners/whatsminer/btminer/__init__.py | 2 +- 7 files changed, 12 insertions(+), 8 deletions(-) diff --git a/pyasic/data/__init__.py b/pyasic/data/__init__.py index 2cf5f583..005e8303 100644 --- a/pyasic/data/__init__.py +++ b/pyasic/data/__init__.py @@ -22,6 +22,7 @@ import copy from .error_codes import X19Error, WhatsminerError, BraiinsOSError, InnosiliconError + @dataclass class HashBoard: slot: int = 0 @@ -122,7 +123,6 @@ class MinerData: fault_light: Union[bool, None] = None efficiency: int = field(init=False) - def __post_init__(self): self.datetime = datetime.now(timezone.utc).astimezone() @@ -284,6 +284,7 @@ class MinerData: @right_board_temp.setter def right_board_temp(self, val): pass + @property def left_board_chip_temp(self): # noqa - Skip PyCharm inspection if len(self.hashboards) in [2, 3]: diff --git a/pyasic/miners/_backends/bosminer.py b/pyasic/miners/_backends/bosminer.py index 1ec0af66..c4c0906d 100644 --- a/pyasic/miners/_backends/bosminer.py +++ b/pyasic/miners/_backends/bosminer.py @@ -478,7 +478,6 @@ class BOSMiner(BaseMiner): else: data.hashboards[_id].missing = True - if devs: boards = devs[0].get("DEVS") if boards: diff --git a/pyasic/miners/_backends/btminer.py b/pyasic/miners/_backends/btminer.py index 495fd9c8..07f16c8f 100644 --- a/pyasic/miners/_backends/btminer.py +++ b/pyasic/miners/_backends/btminer.py @@ -247,7 +247,9 @@ class BTMiner(BaseMiner): A [`MinerData`][pyasic.data.MinerData] instance containing the miners data. """ data = MinerData( - ip=str(self.ip), ideal_chips=self.nominal_chips * self.ideal_hashboards, ideal_hashboards=self.ideal_hashboards, + ip=str(self.ip), + ideal_chips=self.nominal_chips * self.ideal_hashboards, + ideal_hashboards=self.ideal_hashboards, ) mac = None diff --git a/pyasic/miners/_backends/cgminer.py b/pyasic/miners/_backends/cgminer.py index 0cade4d5..a86ac15c 100644 --- a/pyasic/miners/_backends/cgminer.py +++ b/pyasic/miners/_backends/cgminer.py @@ -179,10 +179,12 @@ class CGMiner(BaseMiner): Returns: A [`MinerData`][pyasic.data.MinerData] instance containing the miners data. """ - data = MinerData(ip=str(self.ip), ideal_chips=self.nominal_chips * self.ideal_hashboards, ideal_hashboards=self.ideal_hashboards, + data = MinerData( + ip=str(self.ip), + ideal_chips=self.nominal_chips * self.ideal_hashboards, + ideal_hashboards=self.ideal_hashboards, ) - board_offset = -1 fan_offset = -1 diff --git a/pyasic/miners/_types/whatsminer/__init__.py b/pyasic/miners/_types/whatsminer/__init__.py index 8f5fbb00..1fd92c64 100644 --- a/pyasic/miners/_types/whatsminer/__init__.py +++ b/pyasic/miners/_types/whatsminer/__init__.py @@ -14,4 +14,4 @@ from .M2X import * from .M3X import * -from .M5X import * \ No newline at end of file +from .M5X import * diff --git a/pyasic/miners/whatsminer/btminer/M5X/__init__.py b/pyasic/miners/whatsminer/btminer/M5X/__init__.py index 37599b27..f1bb1890 100644 --- a/pyasic/miners/whatsminer/btminer/M5X/__init__.py +++ b/pyasic/miners/whatsminer/btminer/M5X/__init__.py @@ -15,4 +15,4 @@ from .M50 import ( BTMinerM50, BTMinerM50VH50, -) \ No newline at end of file +) diff --git a/pyasic/miners/whatsminer/btminer/__init__.py b/pyasic/miners/whatsminer/btminer/__init__.py index 8f5fbb00..1fd92c64 100644 --- a/pyasic/miners/whatsminer/btminer/__init__.py +++ b/pyasic/miners/whatsminer/btminer/__init__.py @@ -14,4 +14,4 @@ from .M2X import * from .M3X import * -from .M5X import * \ No newline at end of file +from .M5X import * From b0fc11bcc1d0241d11b28d35aed1d2a5c4ce3ca5 Mon Sep 17 00:00:00 2001 From: Upstream Data Date: Sat, 5 Nov 2022 09:50:03 -0600 Subject: [PATCH 16/30] bug: fix M34S+ not having ideal board count. --- pyasic/miners/_types/whatsminer/M3X/M34S_Plus.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyasic/miners/_types/whatsminer/M3X/M34S_Plus.py b/pyasic/miners/_types/whatsminer/M3X/M34S_Plus.py index 64182846..355fbe2d 100644 --- a/pyasic/miners/_types/whatsminer/M3X/M34S_Plus.py +++ b/pyasic/miners/_types/whatsminer/M3X/M34S_Plus.py @@ -20,7 +20,7 @@ class M34SPlus(BaseMiner): super().__init__() self.ip = ip self.model = "M34S+" - # TODO: has 4 boards instead of 3 + self.ideal_hashboards = 4 self.nominal_chips = 464 self.fan_count = 2 @@ -30,5 +30,6 @@ class M34SPlusVE10(BaseMiner): super().__init__() self.ip = ip self.model = "M34S+ VE10" + self.ideal_hashboards = 4 self.nominal_chips = 464 self.fan_count = 2 From 5dc19dbd78f1a4252a4bff09f76523e914dba7af Mon Sep 17 00:00:00 2001 From: Upstream Data Date: Sat, 5 Nov 2022 10:03:02 -0600 Subject: [PATCH 17/30] feature: add support for avalonminers using new hashboard model. --- .../miners/avalonminer/cgminer/A10X/A10X.py | 43 +++++++++--------- pyasic/miners/avalonminer/cgminer/A7X/A7X.py | 45 ++++++++++--------- pyasic/miners/avalonminer/cgminer/A8X/A8X.py | 45 ++++++++++--------- pyasic/miners/avalonminer/cgminer/A9X/A921.py | 45 ++++++++++--------- 4 files changed, 91 insertions(+), 87 deletions(-) diff --git a/pyasic/miners/avalonminer/cgminer/A10X/A10X.py b/pyasic/miners/avalonminer/cgminer/A10X/A10X.py index d4073da1..1fafb72d 100644 --- a/pyasic/miners/avalonminer/cgminer/A10X/A10X.py +++ b/pyasic/miners/avalonminer/cgminer/A10X/A10X.py @@ -81,7 +81,15 @@ class CGMinerA10X(CGMiner): return mac async def get_data(self): - data = MinerData(ip=str(self.ip), ideal_chips=self.nominal_chips * 3) + data = MinerData( + ip=str(self.ip), + ideal_chips=self.nominal_chips * self.ideal_hashboards, + ideal_hashboards=self.ideal_hashboards, + hashboards=[ + HashBoard(slot=i, expected_chips=self.nominal_chips) + for i in range(self.ideal_hashboards) + ], + ) model = await self.get_model() mac = None @@ -145,27 +153,20 @@ class CGMinerA10X(CGMiner): f"fan_{fan+1}", int(raw_data[f"Fan{fan+1}"]), ) - if "MTmax" in raw_data.keys(): - data.left_board_chip_temp = int(raw_data["MTmax"][0]) - data.center_board_chip_temp = int(raw_data["MTmax"][1]) - data.right_board_chip_temp = int(raw_data["MTmax"][2]) - if "MTavg" in raw_data.keys(): - data.left_board_temp = int(raw_data["MTavg"][0]) - data.center_board_temp = int(raw_data["MTavg"][1]) - data.right_board_temp = int(raw_data["MTavg"][2]) + for board in range(self.ideal_hashboards): + chip_temp = raw_data.get("MTmax") + if chip_temp: + data.hashboards[board].chip_temp = chip_temp[board] - if "PVT_T0" in raw_data: - data.left_chips = len( - [item for item in raw_data["PVT_T0"] if not item == "0"] - ) - if "PVT_T1" in raw_data: - data.center_chips = len( - [item for item in raw_data["PVT_T1"] if not item == "0"] - ) - if "PVT_T2" in raw_data: - data.right_chips = len( - [item for item in raw_data["PVT_T2"] if not item == "0"] - ) + temp = raw_data.get("MTavg") + if temp: + data.hashboards[board].temp = temp[board] + + chips = raw_data.get(f"PVT_T{board}") + if chips: + data.hashboards[board].chips = len( + [item for item in chips if not item == "0"] + ) if pools: pool_1 = None diff --git a/pyasic/miners/avalonminer/cgminer/A7X/A7X.py b/pyasic/miners/avalonminer/cgminer/A7X/A7X.py index 459b4af7..0802aa46 100644 --- a/pyasic/miners/avalonminer/cgminer/A7X/A7X.py +++ b/pyasic/miners/avalonminer/cgminer/A7X/A7X.py @@ -14,7 +14,7 @@ from pyasic.miners._backends import CGMiner # noqa - Ignore access to _module -from pyasic.data import MinerData +from pyasic.data import MinerData, HashBoard from pyasic.settings import PyasicSettings import re from pyasic.config import MinerConfig @@ -81,7 +81,15 @@ class CGMinerA7X(CGMiner): return mac async def get_data(self): - data = MinerData(ip=str(self.ip), ideal_chips=self.nominal_chips * 3) + data = MinerData( + ip=str(self.ip), + ideal_chips=self.nominal_chips * self.ideal_hashboards, + ideal_hashboards=self.ideal_hashboards, + hashboards=[ + HashBoard(slot=i, expected_chips=self.nominal_chips) + for i in range(self.ideal_hashboards) + ], + ) model = await self.get_model() mac = None @@ -145,27 +153,20 @@ class CGMinerA7X(CGMiner): f"fan_{fan+1}", int(raw_data[f"Fan{fan+1}"]), ) - if "MTmax" in raw_data.keys(): - data.left_board_chip_temp = int(raw_data["MTmax"][0]) - data.center_board_chip_temp = int(raw_data["MTmax"][1]) - data.right_board_chip_temp = int(raw_data["MTmax"][2]) - if "MTavg" in raw_data.keys(): - data.left_board_temp = int(raw_data["MTavg"][0]) - data.center_board_temp = int(raw_data["MTavg"][1]) - data.right_board_temp = int(raw_data["MTavg"][2]) + for board in range(self.ideal_hashboards): + chip_temp = raw_data.get("MTmax") + if chip_temp: + data.hashboards[board].chip_temp = chip_temp[board] - if "PVT_T0" in raw_data: - data.left_chips = len( - [item for item in raw_data["PVT_T0"] if not item == "0"] - ) - if "PVT_T1" in raw_data: - data.center_chips = len( - [item for item in raw_data["PVT_T1"] if not item == "0"] - ) - if "PVT_T2" in raw_data: - data.right_chips = len( - [item for item in raw_data["PVT_T2"] if not item == "0"] - ) + temp = raw_data.get("MTavg") + if temp: + data.hashboards[board].temp = temp[board] + + chips = raw_data.get(f"PVT_T{board}") + if chips: + data.hashboards[board].chips = len( + [item for item in chips if not item == "0"] + ) if pools: pool_1 = None diff --git a/pyasic/miners/avalonminer/cgminer/A8X/A8X.py b/pyasic/miners/avalonminer/cgminer/A8X/A8X.py index 1f47cb42..1c01c185 100644 --- a/pyasic/miners/avalonminer/cgminer/A8X/A8X.py +++ b/pyasic/miners/avalonminer/cgminer/A8X/A8X.py @@ -14,7 +14,7 @@ from pyasic.miners._backends import CGMiner # noqa - Ignore access to _module -from pyasic.data import MinerData +from pyasic.data import MinerData, HashBoard from pyasic.settings import PyasicSettings import re from pyasic.config import MinerConfig @@ -81,7 +81,15 @@ class CGMinerA8X(CGMiner): return mac async def get_data(self): - data = MinerData(ip=str(self.ip), ideal_chips=self.nominal_chips * 3) + data = MinerData( + ip=str(self.ip), + ideal_chips=self.nominal_chips * self.ideal_hashboards, + ideal_hashboards=self.ideal_hashboards, + hashboards=[ + HashBoard(slot=i, expected_chips=self.nominal_chips) + for i in range(self.ideal_hashboards) + ], + ) model = await self.get_model() mac = None @@ -145,27 +153,20 @@ class CGMinerA8X(CGMiner): f"fan_{fan+1}", int(raw_data[f"Fan{fan+1}"]), ) - if "MTmax" in raw_data.keys(): - data.left_board_chip_temp = int(raw_data["MTmax"][0]) - data.center_board_chip_temp = int(raw_data["MTmax"][1]) - data.right_board_chip_temp = int(raw_data["MTmax"][2]) - if "MTavg" in raw_data.keys(): - data.left_board_temp = int(raw_data["MTavg"][0]) - data.center_board_temp = int(raw_data["MTavg"][1]) - data.right_board_temp = int(raw_data["MTavg"][2]) + for board in range(self.ideal_hashboards): + chip_temp = raw_data.get("MTmax") + if chip_temp: + data.hashboards[board].chip_temp = chip_temp[board] - if "PVT_T0" in raw_data: - data.left_chips = len( - [item for item in raw_data["PVT_T0"] if not item == "0"] - ) - if "PVT_T1" in raw_data: - data.center_chips = len( - [item for item in raw_data["PVT_T1"] if not item == "0"] - ) - if "PVT_T2" in raw_data: - data.right_chips = len( - [item for item in raw_data["PVT_T2"] if not item == "0"] - ) + temp = raw_data.get("MTavg") + if temp: + data.hashboards[board].temp = temp[board] + + chips = raw_data.get(f"PVT_T{board}") + if chips: + data.hashboards[board].chips = len( + [item for item in chips if not item == "0"] + ) if pools: pool_1 = None diff --git a/pyasic/miners/avalonminer/cgminer/A9X/A921.py b/pyasic/miners/avalonminer/cgminer/A9X/A921.py index 959bc3f7..79e984d8 100644 --- a/pyasic/miners/avalonminer/cgminer/A9X/A921.py +++ b/pyasic/miners/avalonminer/cgminer/A9X/A921.py @@ -15,7 +15,7 @@ from pyasic.miners._backends import CGMiner # noqa - Ignore access to _module from pyasic.miners._types import Avalon921 # noqa - Ignore access to _module -from pyasic.data import MinerData +from pyasic.data import MinerData, HashBoard from pyasic.settings import PyasicSettings import re from pyasic.config import MinerConfig @@ -82,7 +82,15 @@ class CGMinerAvalon921(CGMiner, Avalon921): return mac async def get_data(self): - data = MinerData(ip=str(self.ip), ideal_chips=self.nominal_chips * 3) + data = MinerData( + ip=str(self.ip), + ideal_chips=self.nominal_chips * self.ideal_hashboards, + ideal_hashboards=self.ideal_hashboards, + hashboards=[ + HashBoard(slot=i, expected_chips=self.nominal_chips) + for i in range(self.ideal_hashboards) + ], + ) model = await self.get_model() mac = None @@ -146,27 +154,20 @@ class CGMinerAvalon921(CGMiner, Avalon921): f"fan_{fan+1}", int(raw_data[f"Fan{fan+1}"]), ) - if "MTmax" in raw_data.keys(): - data.left_board_chip_temp = int(raw_data["MTmax"][0]) - data.center_board_chip_temp = int(raw_data["MTmax"][1]) - data.right_board_chip_temp = int(raw_data["MTmax"][2]) - if "MTavg" in raw_data.keys(): - data.left_board_temp = int(raw_data["MTavg"][0]) - data.center_board_temp = int(raw_data["MTavg"][1]) - data.right_board_temp = int(raw_data["MTavg"][2]) + for board in range(self.ideal_hashboards): + chip_temp = raw_data.get("MTmax") + if chip_temp: + data.hashboards[board].chip_temp = chip_temp[board] - if "PVT_T0" in raw_data: - data.left_chips = len( - [item for item in raw_data["PVT_T0"] if not item == "0"] - ) - if "PVT_T1" in raw_data: - data.center_chips = len( - [item for item in raw_data["PVT_T1"] if not item == "0"] - ) - if "PVT_T2" in raw_data: - data.right_chips = len( - [item for item in raw_data["PVT_T2"] if not item == "0"] - ) + temp = raw_data.get("MTavg") + if temp: + data.hashboards[board].temp = temp[board] + + chips = raw_data.get(f"PVT_T{board}") + if chips: + data.hashboards[board].chips = len( + [item for item in chips if not item == "0"] + ) if pools: pool_1 = None From 92f58a9682644759e2babc22dac18f27a85e5a72 Mon Sep 17 00:00:00 2001 From: Upstream Data Date: Sat, 5 Nov 2022 10:04:17 -0600 Subject: [PATCH 18/30] bug: fix fan count and ideal chips for M34S+. --- pyasic/miners/_types/whatsminer/M3X/M34S_Plus.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pyasic/miners/_types/whatsminer/M3X/M34S_Plus.py b/pyasic/miners/_types/whatsminer/M3X/M34S_Plus.py index 355fbe2d..f73222a4 100644 --- a/pyasic/miners/_types/whatsminer/M3X/M34S_Plus.py +++ b/pyasic/miners/_types/whatsminer/M3X/M34S_Plus.py @@ -21,8 +21,8 @@ class M34SPlus(BaseMiner): self.ip = ip self.model = "M34S+" self.ideal_hashboards = 4 - self.nominal_chips = 464 - self.fan_count = 2 + self.nominal_chips = 116 + self.fan_count = 0 class M34SPlusVE10(BaseMiner): @@ -31,5 +31,5 @@ class M34SPlusVE10(BaseMiner): self.ip = ip self.model = "M34S+ VE10" self.ideal_hashboards = 4 - self.nominal_chips = 464 - self.fan_count = 2 + self.nominal_chips = 116 + self.fan_count = 0 From c6ca1df112cf88c068b61c695282389d91e104ad Mon Sep 17 00:00:00 2001 From: Upstream Data Date: Sat, 5 Nov 2022 10:15:18 -0600 Subject: [PATCH 19/30] bug: fix some issues with get data on X19 from CGMiner on Vnish to BMMiner on stock. --- pyasic/API/cgminer.py | 35 +++++++++++++++++++++++++++++- pyasic/miners/_backends/bmminer.py | 7 +++--- pyasic/miners/_backends/cgminer.py | 9 ++++---- 3 files changed, 43 insertions(+), 8 deletions(-) diff --git a/pyasic/API/cgminer.py b/pyasic/API/cgminer.py index 0ec70bb4..cac318d6 100644 --- a/pyasic/API/cgminer.py +++ b/pyasic/API/cgminer.py @@ -12,7 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -from pyasic.API import BaseMinerAPI +from pyasic.API import BaseMinerAPI, APIError + +import logging class CGMinerAPI(BaseMinerAPI): @@ -36,6 +38,37 @@ class CGMinerAPI(BaseMinerAPI): def __init__(self, ip: str, port: int = 4028): super().__init__(ip, port) + async def multicommand( + self, *commands: str, ignore_x19_error: bool = False + ) -> dict: + logging.debug(f"{self.ip}: Sending multicommand: {[*commands]}") + # make sure we can actually run each command, otherwise they will fail + commands = self._check_commands(*commands) + # standard multicommand format is "command1+command2" + # doesnt work for S19 which uses the backup _x19_multicommand + command = "+".join(commands) + try: + data = await self.send_command(command, allow_warning=ignore_x19_error) + except APIError: + logging.debug(f"{self.ip}: Handling X19 multicommand.") + data = await self._x19_multicommand(*command.split("+")) + logging.debug(f"{self.ip}: Received multicommand data.") + return data + + async def _x19_multicommand(self, *commands): + data = None + try: + data = {} + # send all commands individually + for cmd in commands: + data[cmd] = [] + data[cmd].append(await self.send_command(cmd, allow_warning=True)) + except APIError as e: + raise APIError(e) + except Exception as e: + logging.warning(f"{self.ip}: API Multicommand Error: {e}") + return data + async def version(self) -> dict: """Get miner version info.
diff --git a/pyasic/miners/_backends/bmminer.py b/pyasic/miners/_backends/bmminer.py index 469dd671..7da49dec 100644 --- a/pyasic/miners/_backends/bmminer.py +++ b/pyasic/miners/_backends/bmminer.py @@ -281,12 +281,13 @@ class BMMiner(BaseMiner): if (not chips) or (not chips > 0): hashboard.missing = True data.hashboards.append(hashboard) - if f"temp_pcb{i}" in temp[1].keys(): - env_temp = temp[1][f"temp_pcb{i}"].split("-")[0] + + if f"temp_pcb{i}" in boards[1].keys(): + env_temp = boards[1][f"temp_pcb{i}"].split("-")[0] if not env_temp == 0: env_temp_list.append(int(env_temp)) if not env_temp_list == []: - data.env_temp = sum(env_temp_list) / len(env_temp_list) + data.env_temp = round(sum(env_temp_list) / len(env_temp_list)) if stats: temp = stats.get("STATS") diff --git a/pyasic/miners/_backends/cgminer.py b/pyasic/miners/_backends/cgminer.py index a86ac15c..22df1b4f 100644 --- a/pyasic/miners/_backends/cgminer.py +++ b/pyasic/miners/_backends/cgminer.py @@ -206,7 +206,7 @@ class CGMiner(BaseMiner): miner_data = None for i in range(PyasicSettings().miner_get_data_retries): miner_data = await self.api.multicommand( - "summary", "pools", "stats", ignore_x19_error=True + "summary", "pools", "stats", ) if miner_data: break @@ -264,12 +264,13 @@ class CGMiner(BaseMiner): if (not chips) or (not chips > 0): hashboard.missing = True data.hashboards.append(hashboard) - if f"temp_pcb{i}" in temp[1].keys(): - env_temp = temp[1][f"temp_pcb{i}"].split("-")[0] + + if f"temp_pcb{i}" in boards[1].keys(): + env_temp = boards[1][f"temp_pcb{i}"].split("-")[0] if not env_temp == 0: env_temp_list.append(int(env_temp)) if not env_temp_list == []: - data.env_temp = sum(env_temp_list) / len(env_temp_list) + data.env_temp = round(sum(env_temp_list) / len(env_temp_list)) if stats: temp = stats.get("STATS") From 8975842f0bb00c68936f2e27db202fb17e4edf64 Mon Sep 17 00:00:00 2001 From: UpstreamData Date: Mon, 7 Nov 2022 08:52:24 -0700 Subject: [PATCH 20/30] bug: fix for some BMMiner models which report no boards causing an error when getting data. --- pyasic/miners/_backends/bmminer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyasic/miners/_backends/bmminer.py b/pyasic/miners/_backends/bmminer.py index 7da49dec..1b8d29da 100644 --- a/pyasic/miners/_backends/bmminer.py +++ b/pyasic/miners/_backends/bmminer.py @@ -246,7 +246,7 @@ class BMMiner(BaseMiner): if stats: boards = stats.get("STATS") if boards: - if len(boards) > 0: + if len(boards) > 1: for board_num in range(1, 16, 5): for _b_num in range(5): b = boards[1].get(f"chain_acn{board_num + _b_num}") From f5ec513ce0e847379637af28521804fec9467833 Mon Sep 17 00:00:00 2001 From: UpstreamData Date: Mon, 7 Nov 2022 09:07:32 -0700 Subject: [PATCH 21/30] bug: fix BMMiner warning when getting data from X19. --- pyasic/API/bmminer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyasic/API/bmminer.py b/pyasic/API/bmminer.py index c18b8072..d02e3072 100644 --- a/pyasic/API/bmminer.py +++ b/pyasic/API/bmminer.py @@ -45,10 +45,10 @@ class BMMinerAPI(BaseMinerAPI): # make sure we can actually run each command, otherwise they will fail commands = self._check_commands(*commands) # standard multicommand format is "command1+command2" - # doesnt work for S19 which uses the backup _x19_multicommand + # doesn't work for S19 which uses the backup _x19_multicommand command = "+".join(commands) try: - data = await self.send_command(command, allow_warning=ignore_x19_error) + data = await self.send_command(command, allow_warning=not ignore_x19_error) except APIError: logging.debug(f"{self.ip}: Handling X19 multicommand.") data = await self._x19_multicommand(*command.split("+")) From 8388d2f4acb8986c464443b0973133daeb4ceab4 Mon Sep 17 00:00:00 2001 From: UpstreamData Date: Mon, 7 Nov 2022 09:37:22 -0700 Subject: [PATCH 22/30] bug: change `MinerData().total_chips` from `reduce` to `sum`, as reduce was causing issues when instantiating `MinerData` with a hashboard list that is empty. --- pyasic/data/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyasic/data/__init__.py b/pyasic/data/__init__.py index 005e8303..a98da54d 100644 --- a/pyasic/data/__init__.py +++ b/pyasic/data/__init__.py @@ -177,7 +177,7 @@ class MinerData: @property def total_chips(self): # noqa - Skip PyCharm inspection - return reduce(lambda x, y: x + y, [hb.chips for hb in self.hashboards]) + return sum([hb.chips for hb in self.hashboards]) @total_chips.setter def total_chips(self, val): From d47e59d057ad4cd8b3332e112cba82391d51417a Mon Sep 17 00:00:00 2001 From: UpstreamData Date: Mon, 7 Nov 2022 10:09:56 -0700 Subject: [PATCH 23/30] bug: fix a bug with older versions of BOSMiner having tuner status in a different place. --- pyasic/miners/_backends/bosminer.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pyasic/miners/_backends/bosminer.py b/pyasic/miners/_backends/bosminer.py index c4c0906d..ab541613 100644 --- a/pyasic/miners/_backends/bosminer.py +++ b/pyasic/miners/_backends/bosminer.py @@ -266,7 +266,11 @@ class BOSMiner(BaseMiner): logging.warning(e) if tunerstatus: - tuner = tunerstatus[0].get("TUNERSTATUS") + print(tunerstatus) + try: + tuner = tunerstatus[0].get("TUNERSTATUS") + except KeyError: + tuner = tunerstatus.get("TUNERSTATUS") if tuner: if len(tuner) > 0: chain_status = tuner[0].get("TunerChainStatus") From 81db6d8e287836c06d8767b9c77d9a63387dd8d4 Mon Sep 17 00:00:00 2001 From: UpstreamData Date: Mon, 7 Nov 2022 10:11:08 -0700 Subject: [PATCH 24/30] format: remove print in tunerstatus. --- pyasic/miners/_backends/bosminer.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pyasic/miners/_backends/bosminer.py b/pyasic/miners/_backends/bosminer.py index ab541613..9a4916be 100644 --- a/pyasic/miners/_backends/bosminer.py +++ b/pyasic/miners/_backends/bosminer.py @@ -266,7 +266,6 @@ class BOSMiner(BaseMiner): logging.warning(e) if tunerstatus: - print(tunerstatus) try: tuner = tunerstatus[0].get("TUNERSTATUS") except KeyError: From cf3b2fedf47bcbc4973484cdbc9d0b3129a2254f Mon Sep 17 00:00:00 2001 From: UpstreamData Date: Mon, 7 Nov 2022 10:18:22 -0700 Subject: [PATCH 25/30] bug: fix a missed key step in btminer get errors. --- pyasic/miners/_backends/btminer.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/pyasic/miners/_backends/btminer.py b/pyasic/miners/_backends/btminer.py index 07f16c8f..0b1e43ff 100644 --- a/pyasic/miners/_backends/btminer.py +++ b/pyasic/miners/_backends/btminer.py @@ -171,15 +171,19 @@ class BTMiner(BaseMiner): data.append(WhatsminerError(error_code=int(err))) except APIError: summary_data = await self.api.summary() - if summary_data[0].get("Error Code Count"): - for i in range(summary_data[0]["Error Code Count"]): - if summary_data[0].get(f"Error Code {i}"): - if not summary_data[0][f"Error Code {i}"] == "": - data.append( - WhatsminerError( - error_code=summary_data[0][f"Error Code {i}"] + if summary_data.get("SUMMARY"): + summary_data = summary_data["SUMMARY"] + if summary_data[0].get("Error Code Count"): + print(summary_data[0].get("Error Code Count")) + for i in range(summary_data[0]["Error Code Count"]): + print(i) + if summary_data[0].get(f"Error Code {i}"): + if not summary_data[0][f"Error Code {i}"] == "": + data.append( + WhatsminerError( + error_code=summary_data[0][f"Error Code {i}"] + ) ) - ) return data From 8db81d9b3cd6f4c03597060ba7c93d9182368154 Mon Sep 17 00:00:00 2001 From: UpstreamData Date: Mon, 7 Nov 2022 10:18:50 -0700 Subject: [PATCH 26/30] format: remove prints. --- pyasic/miners/_backends/btminer.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/pyasic/miners/_backends/btminer.py b/pyasic/miners/_backends/btminer.py index 0b1e43ff..b2a419a5 100644 --- a/pyasic/miners/_backends/btminer.py +++ b/pyasic/miners/_backends/btminer.py @@ -109,7 +109,6 @@ class BTMiner(BaseMiner): if "Code" in data.keys(): if data["Code"] == 131: return True - print(data) return False async def check_light(self) -> bool: @@ -174,9 +173,7 @@ class BTMiner(BaseMiner): if summary_data.get("SUMMARY"): summary_data = summary_data["SUMMARY"] if summary_data[0].get("Error Code Count"): - print(summary_data[0].get("Error Code Count")) for i in range(summary_data[0]["Error Code Count"]): - print(i) if summary_data[0].get(f"Error Code {i}"): if not summary_data[0][f"Error Code {i}"] == "": data.append( From b33586f8eb98a88e3dbe3075cf208d4a2771bff1 Mon Sep 17 00:00:00 2001 From: UpstreamData Date: Mon, 7 Nov 2022 10:51:34 -0700 Subject: [PATCH 27/30] feature: add fields() method to `MinerData` dataclass. --- pyasic/data/__init__.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pyasic/data/__init__.py b/pyasic/data/__init__.py index a98da54d..a033c5a7 100644 --- a/pyasic/data/__init__.py +++ b/pyasic/data/__init__.py @@ -13,7 +13,7 @@ # limitations under the License. from typing import Union, List -from dataclasses import dataclass, field, asdict +from dataclasses import dataclass, field, asdict, fields from datetime import datetime, timezone from functools import reduce import time @@ -123,6 +123,11 @@ class MinerData: fault_light: Union[bool, None] = None efficiency: int = field(init=False) + @classmethod + def fields(cls): + return [f.name for f in fields(cls)] + + def __post_init__(self): self.datetime = datetime.now(timezone.utc).astimezone() From 215af72a6ba971b34ba831770bf0914145194641 Mon Sep 17 00:00:00 2001 From: UpstreamData Date: Mon, 7 Nov 2022 12:49:01 -0700 Subject: [PATCH 28/30] feature: add 0 as `error_code` for bos errors and X19 errors to make them consistent with the other types of errors. --- pyasic/data/error_codes/X19.py | 1 + pyasic/data/error_codes/bos.py | 1 + 2 files changed, 2 insertions(+) diff --git a/pyasic/data/error_codes/X19.py b/pyasic/data/error_codes/X19.py index 9707cbfa..9b5e11cc 100644 --- a/pyasic/data/error_codes/X19.py +++ b/pyasic/data/error_codes/X19.py @@ -24,6 +24,7 @@ class X19Error: """ error_message: str + error_code: int = 0 def asdict(self): return asdict(self) diff --git a/pyasic/data/error_codes/bos.py b/pyasic/data/error_codes/bos.py index cdb259a2..4ad78796 100644 --- a/pyasic/data/error_codes/bos.py +++ b/pyasic/data/error_codes/bos.py @@ -24,6 +24,7 @@ class BraiinsOSError: """ error_message: str + error_code: int = 0 def asdict(self): return asdict(self) From c7847d278967821d2747ad1c1481b559087ddc94 Mon Sep 17 00:00:00 2001 From: UpstreamData Date: Mon, 7 Nov 2022 12:53:01 -0700 Subject: [PATCH 29/30] feature: add fields classmethod to all dataclasses to show what the fields are in each class. --- pyasic/config/__init__.py | 14 +++++++++++++- pyasic/data/error_codes/X19.py | 7 ++++++- pyasic/data/error_codes/bos.py | 8 +++++++- pyasic/data/error_codes/innosilicon.py | 7 ++++++- pyasic/data/error_codes/whatsminer.py | 7 ++++++- 5 files changed, 38 insertions(+), 5 deletions(-) diff --git a/pyasic/config/__init__.py b/pyasic/config/__init__.py index a508d819..4fa575f7 100644 --- a/pyasic/config/__init__.py +++ b/pyasic/config/__init__.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from dataclasses import dataclass, asdict +from dataclasses import dataclass, asdict, fields from typing import Literal, List import random import string @@ -37,6 +37,10 @@ class _Pool: username: str = "" password: str = "" + @classmethod + def fields(cls): + return fields(cls) + def from_dict(self, data: dict): """Convert raw pool data as a dict to usable data and save it to this class. @@ -136,6 +140,10 @@ class _PoolGroup: group_name: str = None pools: List[_Pool] = None + @classmethod + def fields(cls): + return fields(cls) + def __post_init__(self): if not self.group_name: self.group_name = "".join( @@ -263,6 +271,10 @@ class MinerConfig: dps_shutdown_enabled: bool = None dps_shutdown_duration: float = None + @classmethod + def fields(cls): + return fields(cls) + def as_dict(self) -> dict: """Convert the data in this class to a dict.""" data_dict = asdict(self) diff --git a/pyasic/data/error_codes/X19.py b/pyasic/data/error_codes/X19.py index 9b5e11cc..852848bf 100644 --- a/pyasic/data/error_codes/X19.py +++ b/pyasic/data/error_codes/X19.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from dataclasses import dataclass, asdict +from dataclasses import dataclass, asdict, fields @dataclass @@ -21,10 +21,15 @@ class X19Error: Attributes: error_message: The error message as a string. + error_code: The error code as an int. 0 if the message is not assigned a code. """ error_message: str error_code: int = 0 + @classmethod + def fields(cls): + return fields(cls) + def asdict(self): return asdict(self) diff --git a/pyasic/data/error_codes/bos.py b/pyasic/data/error_codes/bos.py index 4ad78796..abe10dfb 100644 --- a/pyasic/data/error_codes/bos.py +++ b/pyasic/data/error_codes/bos.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from dataclasses import dataclass, asdict +from dataclasses import dataclass, asdict, fields @dataclass @@ -21,10 +21,16 @@ class BraiinsOSError: Attributes: error_message: The error message as a string. + error_code: The error code as an int. 0 if the message is not assigned a code. """ error_message: str error_code: int = 0 + @classmethod + def fields(cls): + return fields(cls) + + def asdict(self): return asdict(self) diff --git a/pyasic/data/error_codes/innosilicon.py b/pyasic/data/error_codes/innosilicon.py index 5d275aa4..c779efe1 100644 --- a/pyasic/data/error_codes/innosilicon.py +++ b/pyasic/data/error_codes/innosilicon.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from dataclasses import dataclass, field, asdict +from dataclasses import dataclass, field, asdict, fields @dataclass @@ -27,6 +27,11 @@ class InnosiliconError: error_code: int error_message: str = field(init=False) + @classmethod + def fields(cls): + return fields(cls) + + @property def error_message(self): # noqa - Skip PyCharm inspection if self.error_code in ERROR_CODES: diff --git a/pyasic/data/error_codes/whatsminer.py b/pyasic/data/error_codes/whatsminer.py index 55effa3a..5c2a909a 100644 --- a/pyasic/data/error_codes/whatsminer.py +++ b/pyasic/data/error_codes/whatsminer.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from dataclasses import dataclass, field, asdict +from dataclasses import dataclass, field, asdict, fields @dataclass @@ -27,6 +27,11 @@ class WhatsminerError: error_code: int error_message: str = field(init=False) + + @classmethod + def fields(cls): + return fields(cls) + @property def error_message(self): # noqa - Skip PyCharm inspection if self.error_code in ERROR_CODES: From 6051a46654bc3ee903d4512004a5505e73f8bb6d Mon Sep 17 00:00:00 2001 From: UpstreamData Date: Mon, 7 Nov 2022 12:54:40 -0700 Subject: [PATCH 30/30] docs: update docs to show `cls.fields()` --- docs/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index 770485b9..e96e4bff 100644 --- a/docs/index.md +++ b/docs/index.md @@ -230,7 +230,7 @@ These functions are ## [`MinerConfig`][pyasic.config.MinerConfig] and [`MinerData`][pyasic.data.MinerData] -Pyasic implements a few dataclasses as helpers to make data return types consistent across different miners and miner APIs. +Pyasic implements a few dataclasses as helpers to make data return types consistent across different miners and miner APIs. The different fields of these dataclasses can all be viewed with the classmethod `cls.fields()`.