feature: add custom hashrate types and conversion.

This commit is contained in:
Upstream Data
2024-05-09 15:01:40 -06:00
parent 8ad6f60757
commit 99ff28d3e1
24 changed files with 314 additions and 108 deletions

View File

@@ -28,6 +28,7 @@ from .boards import HashBoard
from .device import DeviceInfo from .device import DeviceInfo
from .error_codes import BraiinsOSError, InnosiliconError, WhatsminerError, X19Error from .error_codes import BraiinsOSError, InnosiliconError, WhatsminerError, X19Error
from .fans import Fan from .fans import Fan
from .hashrate import AlgoHashRate, HashUnit
@dataclass @dataclass
@@ -40,6 +41,10 @@ class MinerData:
uptime: The uptime of the miner in seconds. uptime: The uptime of the miner in seconds.
mac: The MAC address of the miner as a str. mac: The MAC address of the miner as a str.
device_info: Info about the device, such as model, make, and firmware. device_info: Info about the device, such as model, make, and firmware.
model: The model of the miner as a str.
make: The make of the miner as a str.
firmware: The firmware on the miner as a str.
algo: The mining algorithm of the miner as a str.
api_ver: The current api version on the miner as a str. api_ver: The current api version on the miner as a str.
fw_ver: The current firmware version on the miner as a str. fw_ver: The current firmware version on the miner as a str.
hostname: The network hostname of the miner as a str. hostname: The network hostname of the miner as a str.
@@ -78,14 +83,15 @@ class MinerData:
make: str = field(init=False) make: str = field(init=False)
model: str = field(init=False) model: str = field(init=False)
firmware: str = field(init=False) firmware: str = field(init=False)
algo: str = field(init=False)
mac: str = None mac: str = None
api_ver: str = None api_ver: str = None
fw_ver: str = None fw_ver: str = None
hostname: str = None hostname: str = None
# hashrate # hashrate
hashrate: float = field(init=False) hashrate: AlgoHashRate = field(init=False)
_hashrate: float = field(repr=False, default=None) _hashrate: AlgoHashRate = field(repr=False, default=None)
# expected # expected
expected_hashrate: float = None expected_hashrate: float = None
@@ -212,7 +218,7 @@ class MinerData:
if item.hashrate is not None: if item.hashrate is not None:
hr_data.append(item.hashrate) hr_data.append(item.hashrate)
if len(hr_data) > 0: if len(hr_data) > 0:
return round(sum(hr_data), 2) return sum(hr_data, start=type(hr_data[0])(0))
return self._hashrate return self._hashrate
@hashrate.setter @hashrate.setter
@@ -313,7 +319,7 @@ class MinerData:
return None return None
if self.hashrate == 0 or self.wattage == 0: if self.hashrate == 0 or self.wattage == 0:
return 0 return 0
return round(self.wattage / self.hashrate) return round(self.wattage / float(self.hashrate))
@efficiency.setter @efficiency.setter
def efficiency(self, val): def efficiency(self, val):
@@ -362,6 +368,15 @@ class MinerData:
def firmware(self, val): def firmware(self, val):
pass pass
@property
def algo(self): # noqa - Skip PyCharm inspection
if self.device_info.algo is not None:
return str(self.device_info.algo)
@algo.setter
def algo(self, val):
pass
def asdict(self) -> dict: def asdict(self) -> dict:
return asdict(self, dict_factory=self.dict_factory) return asdict(self, dict_factory=self.dict_factory)

View File

@@ -17,6 +17,8 @@
from dataclasses import dataclass from dataclasses import dataclass
from typing import Any from typing import Any
from .hashrate import AlgoHashRate
@dataclass @dataclass
class HashBoard: class HashBoard:
@@ -34,7 +36,7 @@ class HashBoard:
""" """
slot: int = 0 slot: int = 0
hashrate: float = None hashrate: AlgoHashRate = None
temp: int = None temp: int = None
chip_temp: int = None chip_temp: int = None
chips: int = None chips: int = None

View File

@@ -1,5 +1,6 @@
from dataclasses import dataclass from dataclasses import dataclass
from pyasic.device.algorithm import MinerAlgo
from pyasic.device.firmware import MinerFirmware from pyasic.device.firmware import MinerFirmware
from pyasic.device.makes import MinerMake from pyasic.device.makes import MinerMake
from pyasic.device.models import MinerModel from pyasic.device.models import MinerModel
@@ -10,3 +11,4 @@ class DeviceInfo:
make: MinerMake = None make: MinerMake = None
model: MinerModel = None model: MinerModel = None
firmware: MinerFirmware = None firmware: MinerFirmware = None
algo: MinerAlgo = None

View File

@@ -0,0 +1,15 @@
from enum import Enum
from pyasic.data.hashrate.sha256 import SHA256HashRate
from pyasic.device.algorithm.sha256 import SHA256Unit
class AlgoHashRate(Enum):
SHA256 = SHA256HashRate
def __call__(self, *args, **kwargs):
return self.value(*args, **kwargs)
class HashUnit:
SHA256 = SHA256Unit

View File

@@ -0,0 +1,54 @@
from __future__ import annotations
from dataclasses import dataclass
from pyasic.device.algorithm import MinerAlgo
from pyasic.device.algorithm.sha256 import SHA256Unit
@dataclass
class SHA256HashRate:
rate: float
unit: SHA256Unit = MinerAlgo.SHA256.unit.default
def __float__(self):
return float(self.rate)
def __int__(self):
return int(self.rate)
def __repr__(self):
return f"{self.rate} {str(self.unit)}"
def __round__(self, n: int = None):
return round(self.rate, n)
def __add__(self, other: SHA256HashRate | int | float) -> SHA256HashRate:
if isinstance(other, SHA256HashRate):
return SHA256HashRate(self.rate + other.into(self.unit).rate, self.unit)
return SHA256HashRate(self.rate + other, self.unit)
def __sub__(self, other: SHA256HashRate | int | float) -> SHA256HashRate:
if isinstance(other, SHA256HashRate):
return SHA256HashRate(self.rate - other.into(self.unit).rate, self.unit)
return SHA256HashRate(self.rate - other, self.unit)
def __truediv__(self, other: SHA256HashRate | int | float):
if isinstance(other, SHA256HashRate):
return SHA256HashRate(self.rate / other.into(self.unit).rate, self.unit)
return SHA256HashRate(self.rate / other, self.unit)
def __floordiv__(self, other: SHA256HashRate | int | float):
if isinstance(other, SHA256HashRate):
return SHA256HashRate(self.rate // other.into(self.unit).rate, self.unit)
return SHA256HashRate(self.rate // other, self.unit)
def __mul__(self, other: SHA256HashRate | int | float):
if isinstance(other, SHA256HashRate):
return SHA256HashRate(self.rate * other.into(self.unit).rate, self.unit)
return SHA256HashRate(self.rate * other, self.unit)
def into(self, other: SHA256Unit) -> SHA256HashRate:
return SHA256HashRate(
rate=self.rate / (other.value / self.unit.value), unit=other
)

View File

@@ -1,3 +1,4 @@
from .algorithm import MinerAlgo
from .firmware import MinerFirmware from .firmware import MinerFirmware
from .makes import MinerMake from .makes import MinerMake
from .models import MinerModel from .models import MinerModel

View File

@@ -0,0 +1,5 @@
from pyasic.device.algorithm.sha256 import SHA256Algo
class MinerAlgo:
SHA256 = SHA256Algo

View File

@@ -0,0 +1,69 @@
from __future__ import annotations
from dataclasses import dataclass
from enum import IntEnum
class SHA256Unit(IntEnum):
H = 1
KH = int(H) * 1000
MH = int(KH) * 1000
GH = int(MH) * 1000
TH = int(GH) * 1000
PH = int(TH) * 1000
EH = int(PH) * 1000
ZH = int(EH) * 1000
default = TH
def __str__(self):
if self.value == self.H:
return "H/s"
if self.value == self.KH:
return "KH/s"
if self.value == self.MH:
return "MH/s"
if self.value == self.GH:
return "GH/s"
if self.value == self.TH:
return "TH/s"
if self.value == self.PH:
return "PH/s"
if self.value == self.EH:
return "EH/s"
if self.value == self.ZH:
return "ZH/s"
@classmethod
def from_str(cls, value: str):
if value == "H":
return cls.H
elif value == "KH":
return cls.KH
elif value == "MH":
return cls.MH
elif value == "GH":
return cls.GH
elif value == "TH":
return cls.TH
elif value == "PH":
return cls.PH
elif value == "EH":
return cls.EH
elif value == "ZH":
return cls.ZH
return cls.default
def __repr__(self):
return str(self)
# make this json serializable
class _SHA256Algo(str):
unit = SHA256Unit
def __repr__(self):
return "SHA256Algo"
SHA256Algo = _SHA256Algo("SHA256")

View File

@@ -18,7 +18,7 @@ from typing import List, Optional
import asyncssh import asyncssh
from pyasic.data import HashBoard from pyasic.data import AlgoHashRate, HashBoard, HashUnit
from pyasic.errors import APIError from pyasic.errors import APIError
from pyasic.miners.backends import Hiveon from pyasic.miners.backends import Hiveon
from pyasic.miners.data import DataFunction, DataLocations, DataOptions, RPCAPICommand from pyasic.miners.data import DataFunction, DataLocations, DataOptions, RPCAPICommand
@@ -121,7 +121,9 @@ class HiveonT9(Hiveon, T9):
chips += rpc_stats["STATS"][1][f"chain_acn{chipset}"] chips += rpc_stats["STATS"][1][f"chain_acn{chipset}"]
except (KeyError, IndexError): except (KeyError, IndexError):
pass pass
hashboards[board].hashrate = round(hashrate / 1000, 2) hashboards[board].hashrate = AlgoHashRate.SHA256(
hashrate, HashUnit.SHA256.GH
).into(self.algo.unit.default)
hashboards[board].chips = chips hashboards[board].chips = chips
return hashboards return hashboards

View File

@@ -17,7 +17,7 @@
from typing import List, Optional, Union from typing import List, Optional, Union
from pyasic.config import MinerConfig, MiningModeConfig from pyasic.config import MinerConfig, MiningModeConfig
from pyasic.data import Fan, HashBoard from pyasic.data import AlgoHashRate, Fan, HashBoard, HashUnit
from pyasic.data.error_codes import MinerErrorData, X19Error from pyasic.data.error_codes import MinerErrorData, X19Error
from pyasic.errors import APIError from pyasic.errors import APIError
from pyasic.miners.backends.bmminer import BMMiner from pyasic.miners.backends.bmminer import BMMiner
@@ -218,9 +218,9 @@ class AntminerModern(BMMiner):
if rpc_stats is not None: if rpc_stats is not None:
try: try:
for board in rpc_stats["STATS"][0]["chain"]: for board in rpc_stats["STATS"][0]["chain"]:
hashboards[board["index"]].hashrate = round( hashboards[board["index"]].hashrate = AlgoHashRate.SHA256(
board["rate_real"] / 1000, 2 board["rate_real"], HashUnit.SHA256.GH
) ).into(self.algo.unit.default)
hashboards[board["index"]].chips = board["asic_num"] hashboards[board["index"]].chips = board["asic_num"]
board_temp_data = list( board_temp_data = list(
filter(lambda x: not x == 0, board["temp_pcb"]) filter(lambda x: not x == 0, board["temp_pcb"])
@@ -273,12 +273,9 @@ class AntminerModern(BMMiner):
rate_unit = rpc_stats["STATS"][1]["rate_unit"] rate_unit = rpc_stats["STATS"][1]["rate_unit"]
except KeyError: except KeyError:
rate_unit = "GH" rate_unit = "GH"
if rate_unit == "GH": return AlgoHashRate.SHA256(
return round(expected_rate / 1000, 2) expected_rate, HashUnit.SHA256.from_str(rate_unit)
if rate_unit == "MH": ).int(self.algo.unit.default)
return round(expected_rate / 1000000, 2)
else:
return round(expected_rate, 2)
except LookupError: except LookupError:
pass pass
@@ -552,7 +549,9 @@ class AntminerOld(CGMiner):
hashrate = boards[1].get(f"chain_rate{i}") hashrate = boards[1].get(f"chain_rate{i}")
if hashrate: if hashrate:
hashboard.hashrate = round(float(hashrate) / 1000, 2) hashboard.hashrate = AlgoHashRate.SHA256(
hashrate, HashUnit.SHA256.GH
).into(self.algo.unit.default)
chips = boards[1].get(f"chain_acn{i}") chips = boards[1].get(f"chain_acn{i}")
if chips: if chips:

View File

@@ -18,7 +18,7 @@ from enum import Enum
from typing import List, Optional from typing import List, Optional
from pyasic.config import MinerConfig from pyasic.config import MinerConfig
from pyasic.data import Fan, HashBoard from pyasic.data import AlgoHashRate, Fan, HashBoard, HashUnit
from pyasic.errors import APIError from pyasic.errors import APIError
from pyasic.miners.data import ( from pyasic.miners.data import (
DataFunction, DataFunction,
@@ -245,9 +245,9 @@ class Auradine(StockFirmware):
if rpc_summary is not None: if rpc_summary is not None:
try: try:
return round( return AlgoHashRate.SHA256(
float(float(rpc_summary["SUMMARY"][0]["MHS 5s"]) / 1000000), 2 rpc_summary["SUMMARY"][0]["MHS 5s"], HashUnit.SHA256.MH
) ).into(self.algo.unit.default)
except (LookupError, ValueError, TypeError): except (LookupError, ValueError, TypeError):
pass pass
@@ -274,9 +274,9 @@ class Auradine(StockFirmware):
try: try:
for board in rpc_devs["DEVS"]: for board in rpc_devs["DEVS"]:
b_id = board["ID"] - 1 b_id = board["ID"] - 1
hashboards[b_id].hashrate = round( hashboards[b_id].hashrate = AlgoHashRate.SHA256(
float(float(board["MHS 5s"]) / 1000000), 2 board["MHS 5s"], HashUnit.SHA256.MH
) ).into(self.algo.unit.default)
hashboards[b_id].temp = round(float(float(board["Temperature"])), 2) hashboards[b_id].temp = round(float(float(board["Temperature"])), 2)
hashboards[b_id].missing = False hashboards[b_id].missing = False
except LookupError: except LookupError:

View File

@@ -17,7 +17,7 @@
import re import re
from typing import List, Optional from typing import List, Optional
from pyasic.data import Fan, HashBoard from pyasic.data import AlgoHashRate, Fan, HashBoard, HashUnit
from pyasic.errors import APIError from pyasic.errors import APIError
from pyasic.miners.backends.cgminer import CGMiner from pyasic.miners.backends.cgminer import CGMiner
from pyasic.miners.data import DataFunction, DataLocations, DataOptions, RPCAPICommand from pyasic.miners.data import DataFunction, DataLocations, DataOptions, RPCAPICommand
@@ -182,7 +182,9 @@ class AvalonMiner(CGMiner):
if rpc_devs is not None: if rpc_devs is not None:
try: try:
return round(float(rpc_devs["DEVS"][0]["MHS 1m"] / 1000000), 2) return AlgoHashRate.SHA256(
rpc_devs["DEVS"][0]["MHS 1m"], HashUnit.SHA256.MH
).into(self.algo.unit.default)
except (KeyError, IndexError, ValueError, TypeError): except (KeyError, IndexError, ValueError, TypeError):
pass pass
@@ -213,7 +215,9 @@ class AvalonMiner(CGMiner):
try: try:
board_hr = parsed_stats["MGHS"][board] board_hr = parsed_stats["MGHS"][board]
hashboards[board].hashrate = round(float(board_hr) / 1000, 2) hashboards[board].hashrate = AlgoHashRate.SHA256(
board_hr, HashUnit.SHA256.GH
).into(self.algo.unit.default)
except LookupError: except LookupError:
pass pass
@@ -245,7 +249,9 @@ class AvalonMiner(CGMiner):
try: try:
unparsed_stats = rpc_stats["STATS"][0]["MM ID0"] unparsed_stats = rpc_stats["STATS"][0]["MM ID0"]
parsed_stats = self.parse_stats(unparsed_stats) parsed_stats = self.parse_stats(unparsed_stats)
return round(float(parsed_stats["GHSmm"]) / 1000, 2) return AlgoHashRate.SHA256(
parsed_stats["GHSmm"], HashUnit.SHA256.GH
).int(self.algo.unit.default)
except (IndexError, KeyError, ValueError, TypeError): except (IndexError, KeyError, ValueError, TypeError):
pass pass

View File

@@ -17,7 +17,7 @@
from typing import List, Optional from typing import List, Optional
from pyasic.config import MinerConfig from pyasic.config import MinerConfig
from pyasic.data import Fan, HashBoard from pyasic.data import AlgoHashRate, Fan, HashBoard, HashUnit
from pyasic.errors import APIError from pyasic.errors import APIError
from pyasic.miners.data import DataFunction, DataLocations, DataOptions, RPCAPICommand from pyasic.miners.data import DataFunction, DataLocations, DataOptions, RPCAPICommand
from pyasic.miners.device.firmware import StockFirmware from pyasic.miners.device.firmware import StockFirmware
@@ -115,7 +115,9 @@ class BFGMiner(StockFirmware):
if rpc_summary is not None: if rpc_summary is not None:
try: try:
return round(float(rpc_summary["SUMMARY"][0]["MHS 20s"] / 1000000), 2) return AlgoHashRate.SHA256(
rpc_summary["SUMMARY"][0]["MHS 20s"], HashUnit.SHA256.MH
).into(self.algo.unit.default)
except (LookupError, ValueError, TypeError): except (LookupError, ValueError, TypeError):
pass pass
@@ -159,7 +161,9 @@ class BFGMiner(StockFirmware):
hashrate = boards[1].get(f"chain_rate{i}") hashrate = boards[1].get(f"chain_rate{i}")
if hashrate: if hashrate:
hashboard.hashrate = round(float(hashrate) / 1000, 2) hashboard.hashrate = AlgoHashRate.SHA256(
hashrate, HashUnit.SHA256.GH
).into(self.algo.unit.default)
chips = boards[1].get(f"chain_acn{i}") chips = boards[1].get(f"chain_acn{i}")
if chips: if chips:
@@ -218,11 +222,8 @@ class BFGMiner(StockFirmware):
rate_unit = rpc_stats["STATS"][1]["rate_unit"] rate_unit = rpc_stats["STATS"][1]["rate_unit"]
except KeyError: except KeyError:
rate_unit = "GH" rate_unit = "GH"
if rate_unit == "GH": return AlgoHashRate.SHA256(
return round(expected_rate / 1000, 2) expected_rate, HashUnit.SHA256.from_str(rate_unit)
if rate_unit == "MH": ).int(self.algo.unit.default)
return round(expected_rate / 1000000, 2)
else:
return round(expected_rate, 2)
except LookupError: except LookupError:
pass pass

View File

@@ -17,7 +17,7 @@
from typing import List, Optional from typing import List, Optional
from pyasic.config import MinerConfig from pyasic.config import MinerConfig
from pyasic.data import Fan, HashBoard from pyasic.data import AlgoHashRate, Fan, HashBoard, HashUnit
from pyasic.errors import APIError from pyasic.errors import APIError
from pyasic.miners.data import DataFunction, DataLocations, DataOptions, RPCAPICommand from pyasic.miners.data import DataFunction, DataLocations, DataOptions, RPCAPICommand
from pyasic.miners.device.firmware import StockFirmware from pyasic.miners.device.firmware import StockFirmware
@@ -119,7 +119,9 @@ class BMMiner(StockFirmware):
if rpc_summary is not None: if rpc_summary is not None:
try: try:
return round(float(rpc_summary["SUMMARY"][0]["GHS 5s"] / 1000), 2) return AlgoHashRate.SHA256(
rpc_summary["SUMMARY"][0]["GHS 5s"], HashUnit.SHA256.GH
).into(self.algo.unit.default)
except (LookupError, ValueError, TypeError): except (LookupError, ValueError, TypeError):
pass pass
@@ -176,7 +178,9 @@ class BMMiner(StockFirmware):
hashrate = boards[1].get(f"chain_rate{i}") hashrate = boards[1].get(f"chain_rate{i}")
if hashrate: if hashrate:
hashboard.hashrate = round(float(hashrate) / 1000, 2) hashboard.hashrate = AlgoHashRate.SHA256(
hashrate, HashUnit.SHA256.GH
).into(self.algo.unit.default)
chips = boards[1].get(f"chain_acn{i}") chips = boards[1].get(f"chain_acn{i}")
if chips: if chips:
@@ -234,12 +238,9 @@ class BMMiner(StockFirmware):
rate_unit = rpc_stats["STATS"][1]["rate_unit"] rate_unit = rpc_stats["STATS"][1]["rate_unit"]
except KeyError: except KeyError:
rate_unit = "GH" rate_unit = "GH"
if rate_unit == "GH": return AlgoHashRate.SHA256(
return round(expected_rate / 1000, 2) expected_rate, HashUnit.SHA256.from_str(rate_unit)
if rate_unit == "MH": ).int(self.algo.unit.default)
return round(expected_rate / 1000000, 2)
else:
return round(expected_rate, 2)
except LookupError: except LookupError:
pass pass

View File

@@ -21,7 +21,7 @@ import toml
from pyasic.config import MinerConfig from pyasic.config import MinerConfig
from pyasic.config.mining import MiningModePowerTune from pyasic.config.mining import MiningModePowerTune
from pyasic.data import Fan, HashBoard from pyasic.data import AlgoHashRate, Fan, HashBoard, HashUnit
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.data import ( from pyasic.miners.data import (
@@ -349,7 +349,9 @@ class BOSMiner(BraiinsOSFirmware):
if rpc_summary is not None: if rpc_summary is not None:
try: try:
return round(float(rpc_summary["SUMMARY"][0]["MHS 1m"] / 1000000), 2) return AlgoHashRate.SHA256(
rpc_summary["SUMMARY"][0]["MHS 1m"], HashUnit.SHA256.MH
).into(self.algo.unit.default)
except (KeyError, IndexError, ValueError, TypeError): except (KeyError, IndexError, ValueError, TypeError):
pass pass
@@ -419,8 +421,9 @@ class BOSMiner(BraiinsOSFirmware):
for board in rpc_devs["DEVS"]: for board in rpc_devs["DEVS"]:
_id = board["ID"] - offset _id = board["ID"] - offset
hashrate = round(float(board["MHS 1m"] / 1000000), 2) hashboards[_id].hashrate = AlgoHashRate.SHA256(
hashboards[_id].hashrate = hashrate board["MHS 1m"], HashUnit.SHA256.MH
).into(self.algo.unit.default)
except (IndexError, KeyError): except (IndexError, KeyError):
pass pass
@@ -528,11 +531,12 @@ class BOSMiner(BraiinsOSFirmware):
expected_hashrate = round(float(board["Nominal MHS"] / 1000000), 2) expected_hashrate = round(float(board["Nominal MHS"] / 1000000), 2)
if expected_hashrate: if expected_hashrate:
hr_list.append(expected_hashrate) hr_list.append(expected_hashrate)
if len(hr_list) == 0: if len(hr_list) == 0:
return 0 return AlgoHashRate.SHA256(0)
else: else:
return round( return AlgoHashRate.SHA256(
(sum(hr_list) / len(hr_list)) * self.expected_hashboards, 2 (sum(hr_list) / len(hr_list)) * self.expected_hashboards
) )
except (IndexError, KeyError): except (IndexError, KeyError):
pass pass
@@ -783,7 +787,9 @@ class BOSer(BraiinsOSFirmware):
if rpc_summary is not None: if rpc_summary is not None:
try: try:
return round(float(rpc_summary["SUMMARY"][0]["MHS 1m"] / 1000000), 2) return AlgoHashRate.SHA256(
rpc_summary["SUMMARY"][0]["MHS 1m"], HashUnit.SHA256.MH
).into(self.algo.unit.default)
except (KeyError, IndexError, ValueError, TypeError): except (KeyError, IndexError, ValueError, TypeError):
pass pass
@@ -798,7 +804,10 @@ class BOSer(BraiinsOSFirmware):
if grpc_miner_details is not None: if grpc_miner_details is not None:
try: try:
return grpc_miner_details["stickerHashrate"]["gigahashPerSecond"] / 1000 return AlgoHashRate.SHA256(
grpc_miner_details["stickerHashrate"]["gigahashPerSecond"],
HashUnit.SHA256.GH,
).into(self.algo.unit.default)
except LookupError: except LookupError:
pass pass
@@ -827,13 +836,12 @@ class BOSer(BraiinsOSFirmware):
] ]
if board.get("stats") is not None: if board.get("stats") is not None:
if not board["stats"]["realHashrate"]["last5S"] == {}: if not board["stats"]["realHashrate"]["last5S"] == {}:
hashboards[idx].hashrate = round( hashboards[idx].hashrate = AlgoHashRate.SHA256(
board["stats"]["realHashrate"]["last5S"][ board["stats"]["realHashrate"]["last5S"][
"gigahashPerSecond" "gigahashPerSecond"
] ],
/ 1000, HashUnit.SHA256.GH,
2, ).into(self.algo.unit.default)
)
hashboards[idx].missing = False hashboards[idx].missing = False
return hashboards return hashboards

View File

@@ -18,7 +18,7 @@ import logging
from typing import List, Optional from typing import List, Optional
from pyasic.config import MinerConfig, MiningModeConfig from pyasic.config import MinerConfig, MiningModeConfig
from pyasic.data import Fan, HashBoard from pyasic.data import AlgoHashRate, Fan, HashBoard, HashUnit
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.data import DataFunction, DataLocations, DataOptions, RPCAPICommand from pyasic.miners.data import DataFunction, DataLocations, DataOptions, RPCAPICommand
@@ -395,7 +395,9 @@ class BTMiner(StockFirmware):
if rpc_summary is not None: if rpc_summary is not None:
try: try:
return round(float(rpc_summary["SUMMARY"][0]["MHS 1m"] / 1000000), 2) return AlgoHashRate.SHA256(
rpc_summary["SUMMARY"][0]["MHS 1m"], HashUnit.SHA256.MH
).into(self.algo.unit.default)
except LookupError: except LookupError:
pass pass
@@ -423,9 +425,9 @@ class BTMiner(StockFirmware):
self.expected_hashboards += 1 self.expected_hashboards += 1
hashboards[board["ASC"]].chip_temp = round(board["Chip Temp Avg"]) hashboards[board["ASC"]].chip_temp = round(board["Chip Temp Avg"])
hashboards[board["ASC"]].temp = round(board["Temperature"]) hashboards[board["ASC"]].temp = round(board["Temperature"])
hashboards[board["ASC"]].hashrate = round( hashboards[board["ASC"]].hashrate = AlgoHashRate.SHA256(
float(board["MHS 1m"] / 1000000), 2 board["MHS 1m"], HashUnit.SHA256.MH
) ).into(self.algo.unit.default)
hashboards[board["ASC"]].chips = board["Effective Chips"] hashboards[board["ASC"]].chips = board["Effective Chips"]
hashboards[board["ASC"]].serial_number = board["PCB SN"] hashboards[board["ASC"]].serial_number = board["PCB SN"]
hashboards[board["ASC"]].missing = False hashboards[board["ASC"]].missing = False
@@ -571,7 +573,10 @@ class BTMiner(StockFirmware):
try: try:
expected_hashrate = rpc_summary["SUMMARY"][0]["Factory GHS"] expected_hashrate = rpc_summary["SUMMARY"][0]["Factory GHS"]
if expected_hashrate: if expected_hashrate:
return round(expected_hashrate / 1000, 2) return AlgoHashRate.SHA256(
expected_hashrate, HashUnit.SHA256.GH
).int(self.algo.unit.default)
except LookupError: except LookupError:
pass pass

View File

@@ -17,6 +17,7 @@
from typing import Optional from typing import Optional
from pyasic.config import MinerConfig from pyasic.config import MinerConfig
from pyasic.data import AlgoHashRate, HashUnit
from pyasic.errors import APIError from pyasic.errors import APIError
from pyasic.miners.data import DataFunction, DataLocations, DataOptions, RPCAPICommand from pyasic.miners.data import DataFunction, DataLocations, DataOptions, RPCAPICommand
from pyasic.miners.device.firmware import StockFirmware from pyasic.miners.device.firmware import StockFirmware
@@ -117,9 +118,9 @@ class CGMiner(StockFirmware):
if rpc_summary is not None: if rpc_summary is not None:
try: try:
return round( return AlgoHashRate.SHA256(
float(float(rpc_summary["SUMMARY"][0]["GHS 5s"]) / 1000), 2 rpc_summary["SUMMARY"][0]["GHS 5s"], HashUnit.SHA256.GH
) ).into(self.algo.unit.default)
except (LookupError, ValueError, TypeError): except (LookupError, ValueError, TypeError):
pass pass

View File

@@ -17,7 +17,7 @@
from typing import List, Optional from typing import List, Optional
from pyasic.config import MinerConfig from pyasic.config import MinerConfig
from pyasic.data import Fan, HashBoard from pyasic.data import AlgoHashRate, Fan, HashBoard, HashUnit
from pyasic.data.error_codes import MinerErrorData, X19Error from pyasic.data.error_codes import MinerErrorData, X19Error
from pyasic.errors import APIError from pyasic.errors import APIError
from pyasic.logger import logger from pyasic.logger import logger
@@ -227,7 +227,9 @@ class ePIC(ePICFirmware):
if web_summary["HBs"] is not None: if web_summary["HBs"] is not None:
for hb in web_summary["HBs"]: for hb in web_summary["HBs"]:
hashrate += hb["Hashrate"][0] hashrate += hb["Hashrate"][0]
return round(float(float(hashrate / 1000000)), 2) return AlgoHashRate.SHA256(hashrate, HashUnit.SHA256.MH).into(
HashUnit.SHA256.TH
)
except (LookupError, ValueError, TypeError): except (LookupError, ValueError, TypeError):
pass pass
@@ -249,7 +251,9 @@ class ePIC(ePICFirmware):
ideal = hb["Hashrate"][1] / 100 ideal = hb["Hashrate"][1] / 100
hashrate += hb["Hashrate"][0] / ideal hashrate += hb["Hashrate"][0] / ideal
return round(float(float(hashrate / 1000000)), 2) return AlgoHashRate.SHA256(hashrate, HashUnit.SHA256.GH).int(
self.algo.unit.default
)
except (LookupError, ValueError, TypeError): except (LookupError, ValueError, TypeError):
pass pass
@@ -310,7 +314,9 @@ class ePIC(ePICFirmware):
hashrate = hb["Hashrate"][0] hashrate = hb["Hashrate"][0]
# Update the Hashboard object # Update the Hashboard object
hb_list[hb["Index"]].missing = False hb_list[hb["Index"]].missing = False
hb_list[hb["Index"]].hashrate = round(hashrate / 1000000, 2) hb_list[hb["Index"]].hashrate = AlgoHashRate.SHA256(
hashrate, HashUnit.SHA256.MH
).into(self.algo.unit.default)
hb_list[hb["Index"]].chips = num_of_chips hb_list[hb["Index"]].chips = num_of_chips
hb_list[hb["Index"]].temp = hb["Temperature"] hb_list[hb["Index"]].temp = hb["Temperature"]
return hb_list return hb_list

View File

@@ -16,7 +16,7 @@
from typing import List from typing import List
from pyasic.config import MinerConfig, MiningModeConfig from pyasic.config import MinerConfig, MiningModeConfig
from pyasic.data import HashBoard from pyasic.data import AlgoHashRate, HashBoard, HashUnit
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
@@ -158,9 +158,9 @@ class GoldshellMiner(BFGMiner):
if board.get("ID") is not None: if board.get("ID") is not None:
try: try:
b_id = board["ID"] b_id = board["ID"]
hashboards[b_id].hashrate = round( hashboards[b_id].hashrate = AlgoHashRate.SHA256(
board["MHS 20s"] / 1000000, 2 board["MHS 20s"], HashUnit.SHA256.MH
) ).into(self.algo.unit.default)
hashboards[b_id].temp = board["tstemp-2"] hashboards[b_id].temp = board["tstemp-2"]
hashboards[b_id].missing = False hashboards[b_id].missing = False
except KeyError: except KeyError:

View File

@@ -16,7 +16,7 @@
from typing import List, Optional from typing import List, Optional
from pyasic.config import MinerConfig from pyasic.config import MinerConfig
from pyasic.data import Fan, HashBoard from pyasic.data import AlgoHashRate, Fan, HashBoard, HashUnit
from pyasic.data.error_codes import MinerErrorData from pyasic.data.error_codes import MinerErrorData
from pyasic.data.error_codes.innosilicon import InnosiliconError from pyasic.data.error_codes.innosilicon import InnosiliconError
from pyasic.errors import APIError from pyasic.errors import APIError
@@ -182,20 +182,21 @@ class Innosilicon(CGMiner):
if web_get_all is not None: if web_get_all is not None:
try: try:
if "Hash Rate H" in web_get_all["total_hash"].keys(): if "Hash Rate H" in web_get_all["total_hash"].keys():
return round( return AlgoHashRate.SHA256(
float(web_get_all["total_hash"]["Hash Rate H"] / 1000000000000), web_get_all["total_hash"]["Hash Rate H"], HashUnit.SHA256.H
2, ).into(self.algo.unit.default)
)
elif "Hash Rate" in web_get_all["total_hash"].keys(): elif "Hash Rate" in web_get_all["total_hash"].keys():
return round( return AlgoHashRate.SHA256(
float(web_get_all["total_hash"]["Hash Rate"] / 1000000), 5 web_get_all["total_hash"]["Hash Rate"], HashUnit.SHA256.MH
) ).into(self.algo.unit.default)
except KeyError: except KeyError:
pass pass
if rpc_summary is not None: if rpc_summary is not None:
try: try:
return round(float(rpc_summary["SUMMARY"][0]["MHS 1m"] / 1000000), 2) return AlgoHashRate.SHA256(
rpc_summary["SUMMARY"][0]["MHS 1m"], HashUnit.SHA256.MH
).into(self.algo.unit.default)
except (KeyError, IndexError): except (KeyError, IndexError):
pass pass
@@ -247,9 +248,9 @@ class Innosilicon(CGMiner):
hashrate = board.get("Hash Rate H") hashrate = board.get("Hash Rate H")
if hashrate: if hashrate:
hashboards[idx].hashrate = round( hashboards[idx].hashrate = AlgoHashRate.SHA256(
hashrate / 1000000000000, 2 hashrate, HashUnit.SHA256.H
) ).into(self.algo.unit.default)
chip_temp = board.get("Temp max") chip_temp = board.get("Temp max")
if chip_temp: if chip_temp:

View File

@@ -16,7 +16,7 @@
from typing import List, Optional from typing import List, Optional
from pyasic.config import MinerConfig from pyasic.config import MinerConfig
from pyasic.data import Fan, HashBoard from pyasic.data import AlgoHashRate, Fan, HashBoard, HashUnit
from pyasic.errors import APIError from pyasic.errors import APIError
from pyasic.miners.data import DataFunction, DataLocations, DataOptions, RPCAPICommand from pyasic.miners.data import DataFunction, DataLocations, DataOptions, RPCAPICommand
from pyasic.miners.device.firmware import LuxOSFirmware from pyasic.miners.device.firmware import LuxOSFirmware
@@ -171,7 +171,9 @@ class LUXMiner(LuxOSFirmware):
if rpc_summary is not None: if rpc_summary is not None:
try: try:
return round(float(rpc_summary["SUMMARY"][0]["GHS 5s"] / 1000), 2) return AlgoHashRate.SHA256(
rpc_summary["SUMMARY"][0]["GHS 5s"], HashUnit.SHA256.GH
).into(self.algo.unit.default)
except (LookupError, ValueError, TypeError): except (LookupError, ValueError, TypeError):
pass pass
@@ -215,7 +217,9 @@ class LUXMiner(LuxOSFirmware):
hashrate = boards[1].get(f"chain_rate{i}") hashrate = boards[1].get(f"chain_rate{i}")
if hashrate: if hashrate:
hashboard.hashrate = round(float(hashrate) / 1000, 2) hashboard.hashrate = AlgoHashRate.SHA256(
hashrate, HashUnit.SHA256.GH
).into(self.algo.unit.default)
chips = boards[1].get(f"chain_acn{i}") chips = boards[1].get(f"chain_acn{i}")
if chips: if chips:
@@ -273,12 +277,9 @@ class LUXMiner(LuxOSFirmware):
rate_unit = rpc_stats["STATS"][1]["rate_unit"] rate_unit = rpc_stats["STATS"][1]["rate_unit"]
except KeyError: except KeyError:
rate_unit = "GH" rate_unit = "GH"
if rate_unit == "GH": return AlgoHashRate.SHA256(
return round(expected_rate / 1000, 2) expected_rate, HashUnit.SHA256.from_str(rate_unit)
if rate_unit == "MH": ).int(self.algo.unit.default)
return round(expected_rate / 1000000, 2)
else:
return round(expected_rate, 2)
except LookupError: except LookupError:
pass pass

View File

@@ -2,7 +2,7 @@ from typing import List, Optional
from pyasic import MinerConfig from pyasic import MinerConfig
from pyasic.config import MiningModeConfig from pyasic.config import MiningModeConfig
from pyasic.data import Fan, HashBoard from pyasic.data import AlgoHashRate, Fan, HashBoard, HashUnit
from pyasic.errors import APIError from pyasic.errors import APIError
from pyasic.miners.data import DataFunction, DataLocations, DataOptions, WebAPICommand from pyasic.miners.data import DataFunction, DataLocations, DataOptions, WebAPICommand
from pyasic.miners.device.firmware import MaraFirmware from pyasic.miners.device.firmware import MaraFirmware
@@ -170,7 +170,9 @@ class MaraMiner(MaraFirmware):
try: try:
for hb in web_hashboards["hashboards"]: for hb in web_hashboards["hashboards"]:
idx = hb["index"] idx = hb["index"]
hashboards[idx].hashrate = round(hb["hashrate_average"] / 1000, 2) hashboards[idx].hashrate = AlgoHashRate.SHA256(
hb["hashrate_average"], HashUnit.SHA256.GH
).into(self.algo.unit.default)
hashboards[idx].temp = round( hashboards[idx].temp = round(
sum(hb["temperature_pcb"]) / len(hb["temperature_pcb"]), 2 sum(hb["temperature_pcb"]) / len(hb["temperature_pcb"]), 2
) )
@@ -232,7 +234,9 @@ class MaraMiner(MaraFirmware):
if web_brief is not None: if web_brief is not None:
try: try:
return round(web_brief["hashrate_realtime"], 2) return AlgoHashRate.SHA256(
web_brief["hashrate_realtime"], HashUnit.SHA256.TH
).into(self.algo.unit.default)
except LookupError: except LookupError:
pass pass
@@ -276,7 +280,9 @@ class MaraMiner(MaraFirmware):
if web_brief is not None: if web_brief is not None:
try: try:
return round(web_brief["hashrate_ideal"] / 1000, 2) return AlgoHashRate.SHA256(
web_brief["hashrate_ideal"], HashUnit.SHA256.GH
).int(self.algo.unit.default)
except LookupError: except LookupError:
pass pass

View File

@@ -17,6 +17,7 @@
from typing import Optional from typing import Optional
from pyasic import MinerConfig from pyasic import MinerConfig
from pyasic.data import AlgoHashRate, HashUnit
from pyasic.errors import APIError from pyasic.errors import APIError
from pyasic.miners.backends.bmminer import BMMiner from pyasic.miners.backends.bmminer import BMMiner
from pyasic.miners.data import ( from pyasic.miners.data import (
@@ -186,9 +187,9 @@ class VNish(BMMiner, VNishFirmware):
if rpc_summary is not None: if rpc_summary is not None:
try: try:
return round( return AlgoHashRate.SHA256(
float(float(rpc_summary["SUMMARY"][0]["GHS 5s"]) / 1000), 2 rpc_summary["SUMMARY"][0]["GHS 5s"], HashUnit.SHA256.GH
) ).into(self.algo.unit.default)
except (LookupError, ValueError, TypeError): except (LookupError, ValueError, TypeError):
pass pass

View File

@@ -22,6 +22,8 @@ from pyasic.config import MinerConfig
from pyasic.data import Fan, HashBoard, MinerData from pyasic.data import Fan, HashBoard, MinerData
from pyasic.data.device import DeviceInfo from pyasic.data.device import DeviceInfo
from pyasic.data.error_codes import MinerErrorData from pyasic.data.error_codes import MinerErrorData
from pyasic.device import MinerModel
from pyasic.device.algorithm import MinerAlgo
from pyasic.device.firmware import MinerFirmware from pyasic.device.firmware import MinerFirmware
from pyasic.device.makes import MinerMake from pyasic.device.makes import MinerMake
from pyasic.errors import APIError from pyasic.errors import APIError
@@ -40,8 +42,9 @@ class MinerProtocol(Protocol):
ssh: _ssh_cls = None ssh: _ssh_cls = None
make: MinerMake = None make: MinerMake = None
raw_model: str = None raw_model: MinerModel = None
firmware: MinerFirmware = None firmware: MinerFirmware = None
algo = MinerAlgo.SHA256
expected_hashboards: int = 3 expected_hashboards: int = 3
expected_chips: int = None expected_chips: int = None
@@ -84,7 +87,9 @@ class MinerProtocol(Protocol):
@property @property
def device_info(self) -> DeviceInfo: def device_info(self) -> DeviceInfo:
return DeviceInfo(make=self.make, model=self.raw_model, firmware=self.firmware) return DeviceInfo(
make=self.make, model=self.raw_model, firmware=self.firmware, algo=self.algo
)
@property @property
def api(self): def api(self):