Compare commits

...

68 Commits

Author SHA1 Message Date
Brett Rowan
61623cc44d version: bump version number. 2024-05-19 11:41:43 -06:00
Brett Rowan
a30a726324 bug: fix some issues with boser handlers. 2024-05-19 11:41:10 -06:00
Brett Rowan
0e90ad64cd Merge pull request #145 from Ytemiloluwa/master 2024-05-18 11:08:31 -06:00
ytemiloluwa
53572c6236 add new attributes 2024-05-18 16:53:06 +01:00
Brett Rowan
67da56a03b version: bump version number. 2024-05-17 21:06:23 -06:00
Brett Rowan
be8633185d bug: remove StrEnum references. 2024-05-17 21:02:57 -06:00
Brett Rowan
1d656da2a2 bug: remove StrEnum references. 2024-05-17 21:00:43 -06:00
Upstream Data
189deae3d1 version: bump version number. 2024-05-17 09:05:00 -06:00
Brett Rowan
46188ad52b Merge pull request #146 from UpstreamData/fix_typo
fix typo
2024-05-17 09:02:22 -06:00
John-Paul Compagnone
19e232ddb9 fix typo 2024-05-17 11:01:01 -04:00
ytemiloluwa
5d90b7e938 pools: updated metrics dataclass 2024-05-16 20:20:53 +01:00
ytemiloluwa
3f90799544 update metrics dataclass 2024-05-16 19:25:48 +01:00
Temi
1f70ec0d28 Merge branch 'UpstreamData:master' into master 2024-05-16 19:00:45 +01:00
Upstream Data
c26b78aa01 version: bump version number. 2024-05-16 08:27:38 -06:00
Brett Rowan
0debf16f7c Merge pull request #144 from jpcomps/master
ePIC: bug fixes
2024-05-16 08:27:07 -06:00
John-Paul Compagnone
d7f48d8f9f remove tuned from MinerConfig 2024-05-16 10:26:04 -04:00
ytemiloluwa
58c95559dd pools: dataclass metrics 2024-05-16 14:08:00 +01:00
JP Compagnone
03caa9fe94 Merge branch 'UpstreamData:master' into master 2024-05-15 21:03:32 -04:00
John-Paul Compagnone
afd8697f07 change from optimized to tuned, which is more generic for other FW 2024-05-15 21:03:12 -04:00
Upstream Data
fc77aded28 version: bump version number. 2024-05-15 14:21:27 -06:00
Brett Rowan
a5cafd1fb8 Merge pull request #137 from UpstreamData/dev_data
feature: Improve timestamp serialization,  add device_data to MinerData, and use enums for device information
2024-05-15 14:20:16 -06:00
John-Paul Compagnone
91d504fc1c add Vopt status, fix typo 2024-05-14 23:07:34 -04:00
Upstream Data
db0444a8eb tests: fix tests. 2024-05-14 13:36:26 -06:00
Upstream Data
0cab872baf bug: fix zero division cases with miner data. 2024-05-14 13:34:17 -06:00
Upstream Data
7f191eb2fd feature: add __getitem__ to config. 2024-05-14 13:34:16 -06:00
Upstream Data
52adc2553b feature: add keys to miner data. 2024-05-14 13:34:16 -06:00
Upstream Data
de49fd7e95 refactor: Optimize imports. 2024-05-14 13:34:16 -06:00
Upstream Data
7eb61473a8 feature: add custom hashrate types and conversion. 2024-05-14 13:34:14 -06:00
Upstream Data
f6a134342a feature: rename MinerModels to MinerModel, and add device info in as properties of MinerData. 2024-05-14 13:33:12 -06:00
Upstream Data
1d67e5ed68 refactor: clean and optimize imports. 2024-05-14 13:33:12 -06:00
Upstream Data
7d4aa80966 refactor: move models to pyasic.miners.devices 2024-05-14 13:33:12 -06:00
Upstream Data
742dde622b feature: add device models. 2024-05-14 13:33:12 -06:00
Upstream Data
497aa6a42c feature: add expected fans to miner data. 2024-05-14 13:33:10 -06:00
Upstream Data
40ebf42da1 feature: create device_info field for MinerData. 2024-05-14 13:32:12 -06:00
Upstream Data
2f8aea5285 bug: fix as_influx timestamp parsing. 2024-05-14 13:32:12 -06:00
Upstream Data
53f545ba13 feature: save datetime object as private in MinerData, and parse datetime in ISO format along with a timestamp. 2024-05-14 13:32:08 -06:00
Upstream Data
689b34611e version: bump version number. 2024-05-14 08:48:38 -06:00
Brett Rowan
d55c3f45ef Merge pull request #143 from jpcomps/master
feat: add additional ePIC UMC features, add Output Voltage to MinerData
2024-05-14 08:47:00 -06:00
John-Paul Compagnone
5ac533616f missed chiptune 2024-05-14 10:46:26 -04:00
John-Paul Compagnone
96ea5f5d16 remove passing self 2024-05-14 10:41:18 -04:00
John-Paul Compagnone
87526f5efc change target as well to get 2024-05-13 23:54:41 -04:00
John-Paul Compagnone
d31bafbc0e less lines 2024-05-13 23:51:23 -04:00
John-Paul Compagnone
66bae47bb9 seperate these out 2024-05-13 21:26:15 -04:00
John-Paul Compagnone
7a09b66d4e simplify 2024-05-13 21:22:31 -04:00
John-Paul Compagnone
de5932184f use get and cheap way to do full backwards compat 2024-05-13 21:17:48 -04:00
John-Paul Compagnone
2cba62e050 push self into secondary level 2024-05-13 21:03:26 -04:00
John-Paul Compagnone
c7520d98e0 better descriptions 2024-05-13 17:00:02 -04:00
John-Paul Compagnone
92e9f7bc08 fix typo 2024-05-13 16:57:19 -04:00
Upstream Data
e0becce349 bug: fix zero division cases with miner data. 2024-05-13 14:41:37 -06:00
John-Paul Compagnone
a65c4ba215 feat: add voltage param to minerdata 2024-05-13 15:44:12 -04:00
John-Paul Compagnone
4cd0c3357b remove prints 2024-05-12 16:05:08 -04:00
John-Paul Compagnone
d5cabf8af5 fix: fix send_config for epic, add throttle step and min throttle for Vopt 2024-05-12 14:08:12 -04:00
JP Compagnone
3120de757d Merge branch 'UpstreamData:master' into master 2024-05-12 13:20:50 -04:00
Upstream Data
1d6618c1c0 feature: add __getitem__ to config. 2024-05-10 13:08:45 -06:00
Upstream Data
7126e03f0d feature: add keys to miner data. 2024-05-10 12:55:29 -06:00
Upstream Data
c27556c809 refactor: Optimize imports. 2024-05-09 15:04:36 -06:00
Upstream Data
99ff28d3e1 feature: add custom hashrate types and conversion. 2024-05-09 15:01:40 -06:00
Upstream Data
8ad6f60757 feature: rename MinerModels to MinerModel, and add device info in as properties of MinerData. 2024-05-09 12:48:30 -06:00
Upstream Data
7e02a6b932 refactor: clean and optimize imports. 2024-05-01 14:29:02 -06:00
Upstream Data
60e38fb8bc refactor: move models to pyasic.miners.devices 2024-05-01 14:18:22 -06:00
Upstream Data
4fc2757ffa feature: add device models. 2024-05-01 14:16:49 -06:00
Upstream Data
c89b25d7c9 feature: add expected fans to miner data. 2024-05-01 11:53:45 -06:00
Upstream Data
f2fc354f8c Merge remote-tracking branch 'origin/dev_data' into dev_data 2024-05-01 11:37:00 -06:00
Upstream Data
0e7eca339c feature: create device_info field for MinerData. 2024-05-01 11:36:54 -06:00
Upstream Data
5f76cb9f0a feature: create device_info field for MinerData. 2024-05-01 11:36:28 -06:00
Upstream Data
ed3a4bd32a bug: fix as_influx timestamp parsing. 2024-05-01 10:16:02 -06:00
Upstream Data
a0a1b68f68 feature: save datetime object as private in MinerData, and parse datetime in ISO format along with a timestamp. 2024-05-01 08:57:02 -06:00
John-Paul Compagnone
3b2b586420 add new critical temp api, add board serial no 2024-04-26 19:27:19 -04:00
289 changed files with 3237 additions and 1040 deletions

1180
poetry.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -36,6 +36,12 @@ class MinerConfig:
default_factory=PowerScalingConfig.default
)
def __getitem__(self, item):
try:
return getattr(self, item)
except AttributeError:
raise KeyError
def as_dict(self) -> dict:
"""Converts the MinerConfig object to a dictionary."""
return asdict(self)

View File

@@ -67,6 +67,13 @@ class MinerConfigOption(Enum):
def default(cls):
pass
def __getitem__(self, item):
try:
return getattr(self, item)
except AttributeError:
raise KeyError
@dataclass
class MinerConfigValue:
@@ -112,3 +119,9 @@ class MinerConfigValue:
def as_mara(self) -> dict:
return {}
def __getitem__(self, item):
try:
return getattr(self, item)
except AttributeError:
raise KeyError

View File

@@ -156,6 +156,7 @@ class VOptAlgo(MinerConfigValue):
return "VoltageOptimizer"
@dataclass
class ChipTuneAlgo(MinerConfigValue):
mode: str = field(init=False, default="chip_tune")
@@ -249,6 +250,8 @@ class MiningModePowerTune(MinerConfigValue):
class MiningModeHashrateTune(MinerConfigValue):
mode: str = field(init=False, default="hashrate_tuning")
hashrate: int = None
throttle_limit: int = None
throttle_step: int = None
algo: TunerAlgo = field(default_factory=TunerAlgo.default)
@classmethod
@@ -256,6 +259,10 @@ class MiningModeHashrateTune(MinerConfigValue):
cls_conf = {}
if dict_conf.get("hashrate"):
cls_conf["hashrate"] = dict_conf["hashrate"]
if dict_conf.get("throttle_limit"):
cls_conf["throttle_limit"] = dict_conf["throttle_limit"]
if dict_conf.get("throttle_step"):
cls_conf["throttle_step"] = dict_conf["throttle_step"]
if dict_conf.get("algo"):
cls_conf["algo"] = TunerAlgo.from_dict(dict_conf["algo"])
@@ -292,7 +299,17 @@ class MiningModeHashrateTune(MinerConfigValue):
return {"mode": {"mode": "custom", "tune": "ths", "ths": self.hashrate}}
def as_epic(self) -> dict:
return {"ptune": {"algo": self.algo.as_epic(), "target": self.hashrate}}
mode = {
"ptune": {
"algo": self.algo.as_epic(),
"target": self.hashrate,
}
}
if self.throttle_limit is not None:
mode["ptune"]["min_throttle"] = self.throttle_limit
if self.throttle_step is not None:
mode["ptune"]["throttle_step"] = self.throttle_step
return mode
def as_mara(self) -> dict:
return {
@@ -416,13 +433,19 @@ class MiningModeConfig(MinerConfigOption):
algo_info = web_conf["PerpetualTune"]["Algorithm"]
if algo_info.get("VoltageOptimizer") is not None:
return cls.hashrate_tuning(
hashrate=algo_info["VoltageOptimizer"]["Target"],
algo=TunerAlgo.voltage_optimizer,
hashrate=algo_info["VoltageOptimizer"].get("Target"),
throttle_limit=algo_info["VoltageOptimizer"].get(
"Min Throttle Target"
),
throttle_step=algo_info["VoltageOptimizer"].get(
"Throttle Step"
),
algo=TunerAlgo.voltage_optimizer(),
)
else:
return cls.hashrate_tuning(
hashrate=algo_info["ChipTune"]["Target"],
algo=TunerAlgo.chip_tune,
hashrate=algo_info["ChipTune"].get("Target"),
algo=TunerAlgo.chip_tune(),
)
else:
return cls.normal()

View File

@@ -49,7 +49,9 @@ class TemperatureConfig(MinerConfigValue):
else:
temps_config["fans"]["Auto"]["Target Temperature"] = 60
if self.danger is not None:
temps_config["temps"]["shutdown"] = self.danger
temps_config["temps"]["critical"] = self.danger
if self.hot is not None:
temps_config["temps"]["shutdown"] = self.hot
return temps_config
@classmethod
@@ -74,16 +76,20 @@ class TemperatureConfig(MinerConfigValue):
@classmethod
def from_epic(cls, web_conf: dict) -> "TemperatureConfig":
try:
dangerous_temp = web_conf["Misc"]["Shutdown Temp"]
dangerous_temp = web_conf["Misc"]["Critical Temp"]
except KeyError:
dangerous_temp = None
try:
hot_temp = web_conf["Misc"]["Shutdown Temp"]
except KeyError:
hot_temp = None
# Need to do this in two blocks to avoid KeyError if one is missing
try:
target_temp = web_conf["Fans"]["Fan Mode"]["Auto"]["Target Temperature"]
except KeyError:
target_temp = None
return cls(target=target_temp, danger=dangerous_temp)
return cls(target=target_temp, hot=hot_temp, danger=dangerous_temp)
@classmethod
def from_vnish(cls, web_settings: dict) -> "TemperatureConfig":

View File

@@ -25,8 +25,10 @@ from pyasic.config import MinerConfig
from pyasic.config.mining import MiningModePowerTune
from .boards import HashBoard
from .device import DeviceInfo
from .error_codes import BraiinsOSError, InnosiliconError, WhatsminerError, X19Error
from .fans import Fan
from .hashrate import AlgoHashRate, HashUnit
@dataclass
@@ -38,8 +40,11 @@ class MinerData:
datetime: The time and date this data was generated.
uptime: The uptime of the miner in seconds.
mac: The MAC address of the miner as a str.
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.
fw_ver: The current firmware version on the miner as a str.
hostname: The network hostname of the miner as a str.
@@ -50,8 +55,10 @@ class MinerData:
temperature_avg: The average temperature across the boards. Calculated automatically.
env_temp: The environment temps as a float.
wattage: Current power draw of the miner as an int.
voltage: Current output voltage of the PSU as an float.
wattage_limit: Power limit of the miner as an int.
fans: A list of fans on the miner with their speeds.
expected_fans: The number of fans expected on a miner.
fan_psu: The speed of the PSU on the fan if the miner collects it.
total_chips: The total number of chips on all boards. Calculated automatically.
expected_chips: The expected number of chips in the miner as an int.
@@ -66,34 +73,62 @@ class MinerData:
is_mining: Whether the miner is mining.
"""
# general
ip: str
datetime: datetime = None
uptime: int = None
_datetime: datetime = field(repr=False, default=None)
datetime: str = field(init=False)
timestamp: int = field(init=False)
# about
device_info: DeviceInfo = None
make: str = field(init=False)
model: str = field(init=False)
firmware: str = field(init=False)
algo: str = field(init=False)
mac: str = None
model: str = None
make: str = None
api_ver: str = None
fw_ver: str = None
hostname: str = None
hashrate: float = field(init=False)
_hashrate: float = field(repr=False, default=None)
# hashrate
hashrate: AlgoHashRate = field(init=False)
_hashrate: AlgoHashRate = field(repr=False, default=None)
# expected
expected_hashrate: float = None
hashboards: List[HashBoard] = field(default_factory=list)
expected_hashboards: int = None
temperature_avg: int = field(init=False)
env_temp: float = None
wattage: int = None
wattage_limit: int = field(init=False)
_wattage_limit: int = field(repr=False, default=None)
fans: List[Fan] = field(default_factory=list)
fan_psu: int = None
total_chips: int = field(init=False)
expected_chips: int = None
expected_fans: int = None
# % expected
percent_expected_chips: float = field(init=False)
percent_expected_hashrate: float = field(init=False)
percent_expected_wattage: float = field(init=False)
# temperature
temperature_avg: int = field(init=False)
env_temp: float = None
# power
wattage: int = None
wattage_limit: int = field(init=False)
voltage: float = None
_wattage_limit: int = field(repr=False, default=None)
# fans
fans: List[Fan] = field(default_factory=list)
fan_psu: int = None
# boards
hashboards: List[HashBoard] = field(default_factory=list)
total_chips: int = field(init=False)
nominal: bool = field(init=False)
# config
config: MinerConfig = None
fault_light: Union[bool, None] = None
# errors
errors: List[
Union[
WhatsminerError,
@@ -102,9 +137,11 @@ class MinerData:
InnosiliconError,
]
] = field(default_factory=list)
fault_light: Union[bool, None] = None
efficiency: int = field(init=False)
# mining state
is_mining: bool = True
uptime: int = None
efficiency: int = field(init=False)
@classmethod
def fields(cls):
@@ -115,7 +152,7 @@ class MinerData:
return {k: v for (k, v) in x if not k.startswith("_")}
def __post_init__(self):
self.datetime = datetime.now(timezone.utc).astimezone()
self._datetime = datetime.now(timezone.utc).astimezone()
def get(self, __key: str, default: Any = None):
try:
@@ -183,7 +220,7 @@ class MinerData:
if item.hashrate is not None:
hr_data.append(item.hashrate)
if len(hr_data) > 0:
return round(sum(hr_data), 2)
return sum(hr_data, start=type(hr_data[0])(0))
return self._hashrate
@hashrate.setter
@@ -242,9 +279,10 @@ class MinerData:
def percent_expected_hashrate(self): # noqa - Skip PyCharm inspection
if self.hashrate is None or self.expected_hashrate is None:
return None
if self.hashrate == 0 or self.expected_hashrate == 0:
try:
return round((self.hashrate / self.expected_hashrate) * 100)
except ZeroDivisionError:
return 0
return round((self.hashrate / self.expected_hashrate) * 100)
@percent_expected_hashrate.setter
def percent_expected_hashrate(self, val):
@@ -254,9 +292,10 @@ class MinerData:
def percent_expected_wattage(self): # noqa - Skip PyCharm inspection
if self.wattage_limit is None or self.wattage is None:
return None
if self.wattage_limit == 0 or self.wattage == 0:
try:
return round((self.wattage / self.wattage_limit) * 100)
except ZeroDivisionError:
return 0
return round((self.wattage / self.wattage_limit) * 100)
@percent_expected_wattage.setter
def percent_expected_wattage(self, val):
@@ -282,14 +321,70 @@ class MinerData:
def efficiency(self): # noqa - Skip PyCharm inspection
if self.hashrate is None or self.wattage is None:
return None
if self.hashrate == 0 or self.wattage == 0:
try:
return round(self.wattage / float(self.hashrate))
except ZeroDivisionError:
return 0
return round(self.wattage / self.hashrate)
@efficiency.setter
def efficiency(self, val):
pass
@property
def datetime(self): # noqa - Skip PyCharm inspection
return self._datetime.isoformat()
@datetime.setter
def datetime(self, val):
pass
@property
def timestamp(self): # noqa - Skip PyCharm inspection
return int(time.mktime(self._datetime.timetuple()))
@timestamp.setter
def timestamp(self, val):
pass
@property
def make(self): # noqa - Skip PyCharm inspection
if self.device_info.make is not None:
return str(self.device_info.make)
@make.setter
def make(self, val):
pass
@property
def model(self): # noqa - Skip PyCharm inspection
if self.device_info.model is not None:
return str(self.device_info.model)
@model.setter
def model(self, val):
pass
@property
def firmware(self): # noqa - Skip PyCharm inspection
if self.device_info.firmware is not None:
return str(self.device_info.firmware)
@firmware.setter
def firmware(self, val):
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 keys(self) -> list:
return [f.name for f in fields(self)]
def asdict(self) -> dict:
return asdict(self, dict_factory=self.dict_factory)
@@ -307,9 +402,7 @@ class MinerData:
Returns:
A JSON version of this class.
"""
data = self.asdict()
data["datetime"] = str(int(time.mktime(data["datetime"].timetuple())))
return json.dumps(data)
return json.dumps(self.as_dict())
def as_csv(self) -> str:
"""Get this dataclass as CSV.
@@ -318,7 +411,6 @@ class MinerData:
A CSV version of this class with no headers.
"""
data = self.asdict()
data["datetime"] = str(int(time.mktime(data["datetime"].timetuple())))
errs = []
for error in data["errors"]:
errs.append(error["error_message"])
@@ -383,6 +475,6 @@ class MinerData:
tags_str = ",".join(tag_data)
field_str = ",".join(field_data)
timestamp = str(int(time.mktime(self.datetime.timetuple()) * 1e9))
timestamp = str(self.timestamp * 1e9)
return " ".join([tags_str, field_str, timestamp])

View File

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

14
pyasic/data/device.py Normal file
View File

@@ -0,0 +1,14 @@
from dataclasses import dataclass
from pyasic.device.algorithm import MinerAlgo
from pyasic.device.firmware import MinerFirmware
from pyasic.device.makes import MinerMake
from pyasic.device.models import MinerModel
@dataclass
class DeviceInfo:
make: MinerMake = None
model: MinerModel = 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
)

59
pyasic/data/pools.py Normal file
View File

@@ -0,0 +1,59 @@
from dataclasses import dataclass, field
@dataclass
class PoolMetrics:
"""A dataclass to standardize pool metrics returned from miners.
Attributes:
accepted: Number of accepted shares.
rejected: Number of rejected shares.
get_failures: Number of failures in obtaining work from the pool.
remote_failures: Number of failures communicating with the pool server.
active: Indicates if the miner is connected to the stratum server.
Alive : Indicates if a pool is alive.
url: URL of the pool.
index: Index of the pool.
user: Username for the pool.
pool_rejected_percent: Percentage of rejected shares by the pool.
pool_stale_percent: Percentage of stale shares by the pool.
"""
accepted: int = None
rejected: int = None
get_failures: int = None
remote_failures: int = None
active: bool = None
alive: bool = None
url: str = None
index: int = None
user: str = None
pool_rejected_percent: float = field(init=False)
pool_stale_percent: float = field(init=False)
@property
def pool_rejected_percent(self) -> float: # noqa - Skip PyCharm inspection
"""Calculate and return the percentage of rejected shares"""
return self._calculate_percentage(self.rejected, self.accepted + self.rejected)
@pool_rejected_percent.setter
def pool_rejected_percent(self, val):
pass
@property
def pool_stale_percent(self) -> float: # noqa - Skip PyCharm inspection
"""Calculate and return the percentage of stale shares."""
return self._calculate_percentage(
self.get_failures, self.accepted + self.rejected
)
@pool_stale_percent.setter
def pool_stale_percent(self, val):
pass
@staticmethod
def _calculate_percentage(value: int, total: int) -> float:
"""Calculate the percentage."""
if total == 0:
return 0
return (value / total) * 100

View File

@@ -0,0 +1,4 @@
from .algorithm import MinerAlgo
from .firmware import MinerFirmware
from .makes import MinerMake
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,68 @@
from __future__ import annotations
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")

30
pyasic/device/firmware.py Normal file
View File

@@ -0,0 +1,30 @@
# ------------------------------------------------------------------------------
# Copyright 2022 Upstream Data Inc -
# -
# Licensed under the Apache License, Version 2.0 (the "License"); -
# you may not use this file except in compliance with the License. -
# You may obtain a copy of the License at -
# -
# http://www.apache.org/licenses/LICENSE-2.0 -
# -
# Unless required by applicable law or agreed to in writing, software -
# distributed under the License is distributed on an "AS IS" BASIS, -
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -
# See the License for the specific language governing permissions and -
# limitations under the License. -
# ------------------------------------------------------------------------------
from enum import Enum
class MinerFirmware(str, Enum):
STOCK = "Stock"
BRAIINS_OS = "BOS+"
VNISH = "VNish"
EPIC = "ePIC"
HIVEON = "Hive"
LUXOS = "LuxOS"
MARATHON = "MaraFW"
def __str__(self):
return self.value

30
pyasic/device/makes.py Normal file
View File

@@ -0,0 +1,30 @@
# ------------------------------------------------------------------------------
# Copyright 2022 Upstream Data Inc -
# -
# Licensed under the Apache License, Version 2.0 (the "License"); -
# you may not use this file except in compliance with the License. -
# You may obtain a copy of the License at -
# -
# http://www.apache.org/licenses/LICENSE-2.0 -
# -
# Unless required by applicable law or agreed to in writing, software -
# distributed under the License is distributed on an "AS IS" BASIS, -
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -
# See the License for the specific language governing permissions and -
# limitations under the License. -
# ------------------------------------------------------------------------------
from enum import Enum
class MinerMake(str, Enum):
WHATSMINER = "WhatsMiner"
ANTMINER = "AntMiner"
AVALONMINER = "AvalonMiner"
INNOSILICON = "Innosilicon"
GOLDSHELL = "Goldshell"
AURADINE = "Auradine"
EPIC = "ePIC"
def __str__(self):
return self.value

339
pyasic/device/models.py Normal file
View File

@@ -0,0 +1,339 @@
from enum import Enum
class AntminerModels(str, Enum):
D3 = "D3"
HS3 = "HS3"
L3Plus = "L3+"
DR5 = "DR5"
L7 = "L7"
E9Pro = "E9Pro"
S9 = "S9"
S9i = "S9i"
S9j = "S9j"
T9 = "T9"
Z15 = "Z15"
S17 = "S17"
S17Plus = "S17+"
S17Pro = "S17 Pro"
S17e = "S17e"
T17 = "T17"
T17Plus = "T17+"
T17e = "T17e"
S19 = "S19"
S19NoPIC = "S19 No PIC"
S19L = "S19L"
S19Pro = "S19 Pro"
S19j = "S19j"
S19i = "S19i"
S19Plus = "S19+"
S19jNoPIC = "S19j No PIC"
S19ProPlus = "S19 Pro+"
S19jPro = "S19j Pro"
S19jProNoPIC = "S19j Pro No PIC"
S19jProPlus = "S19j Pro+"
S19jProPlusNoPIC = "S19j Pro+ No PIC"
S19XP = "S19 XP"
S19a = "S19a"
S19aPro = "S19a Pro"
S19Hydro = "S19 Hydro"
S19ProHydro = "S19 Pro Hydro"
S19ProPlusHydro = "S19 Pro+ Hydro"
S19KPro = "S19K Pro"
S19kPro = "S19k Pro"
S19kProNoPIC = "S19k Pro No PIC"
T19 = "T19"
S21 = "S21"
T21 = "T21"
def __str__(self):
return self.value
class WhatsminerModels(str, Enum):
M20V10 = "M20 V10"
M20SV10 = "M20S V10"
M20SV20 = "M20S V20"
M20SV30 = "M20S V30"
M20PV10 = "M20P V10"
M20PV30 = "M20P V30"
M20SPlusV30 = "M20S+ V30"
M21V10 = "M21 V10"
M21SV20 = "M21S V20"
M21SV60 = "M21S V60"
M21SV70 = "M21S V70"
M21SPlusV20 = "M21S+ V20"
M29V10 = "M29 V10"
M30V10 = "M30 V10"
M30V20 = "M30 V20"
M30KV10 = "M30K V10"
M30LV10 = "M30L V10"
M30SV10 = "M30S V10"
M30SV20 = "M30S V20"
M30SV30 = "M30S V30"
M30SV40 = "M30S V40"
M30SV50 = "M30S V50"
M30SV60 = "M30S V60"
M30SV70 = "M30S V70"
M30SV80 = "M30S V80"
M30SVE10 = "M30S VE10"
M30SVE20 = "M30S VE20"
M30SVE30 = "M30S VE30"
M30SVE40 = "M30S VE40"
M30SVE50 = "M30S VE50"
M30SVE60 = "M30S VE60"
M30SVE70 = "M30S VE70"
M30SVF10 = "M30S VF10"
M30SVF20 = "M30S VF20"
M30SVF30 = "M30S VF30"
M30SVG10 = "M30S VG10"
M30SVG20 = "M30S VG20"
M30SVG30 = "M30S VG30"
M30SVG40 = "M30S VG40"
M30SVH10 = "M30S VH10"
M30SVH20 = "M30S VH20"
M30SVH30 = "M30S VH30"
M30SVH40 = "M30S VH40"
M30SVH50 = "M30S VH50"
M30SVH60 = "M30S VH60"
M30SVI20 = "M30S VI20"
M30SPlusV10 = "M30S+ V10"
M30SPlusV20 = "M30S+ V20"
M30SPlusV30 = "M30S+ V30"
M30SPlusV40 = "M30S+ V40"
M30SPlusV50 = "M30S+ V50"
M30SPlusV60 = "M30S+ V60"
M30SPlusV70 = "M30S+ V70"
M30SPlusV80 = "M30S+ V80"
M30SPlusV90 = "M30S+ V90"
M30SPlusV100 = "M30S+ V100"
M30SPlusVE30 = "M30S+ VE30"
M30SPlusVE40 = "M30S+ VE40"
M30SPlusVE50 = "M30S+ VE50"
M30SPlusVE60 = "M30S+ VE60"
M30SPlusVE70 = "M30S+ VE70"
M30SPlusVE80 = "M30S+ VE80"
M30SPlusVE90 = "M30S+ VE90"
M30SPlusVE100 = "M30S+ VE100"
M30SPlusVF20 = "M30S+ VF20"
M30SPlusVF30 = "M30S+ VF30"
M30SPlusVG20 = "M30S+ VG20"
M30SPlusVG30 = "M30S+ VG30"
M30SPlusVG40 = "M30S+ VG40"
M30SPlusVG50 = "M30S+ VG50"
M30SPlusVG60 = "M30S+ VG60"
M30SPlusVH10 = "M30S+ VH10"
M30SPlusVH20 = "M30S+ VH20"
M30SPlusVH30 = "M30S+ VH30"
M30SPlusVH40 = "M30S+ VH40"
M30SPlusVH50 = "M30S+ VH50"
M30SPlusVH60 = "M30S+ VH60"
M30SPlusPlusV10 = "M30S++ V10"
M30SPlusPlusV20 = "M30S++ V20"
M30SPlusPlusVE30 = "M30S++ VE30"
M30SPlusPlusVE40 = "M30S++ VE40"
M30SPlusPlusVE50 = "M30S++ VE50"
M30SPlusPlusVF40 = "M30S++ VF40"
M30SPlusPlusVG30 = "M30S++ VG30"
M30SPlusPlusVG40 = "M30S++ VG40"
M30SPlusPlusVG50 = "M30S++ VG50"
M30SPlusPlusVH10 = "M30S++ VH10"
M30SPlusPlusVH20 = "M30S++ VH20"
M30SPlusPlusVH30 = "M30S++ VH30"
M30SPlusPlusVH40 = "M30S++ VH40"
M30SPlusPlusVH50 = "M30S++ VH50"
M30SPlusPlusVH60 = "M30S++ VH60"
M30SPlusPlusVH70 = "M30S++ VH70"
M30SPlusPlusVH80 = "M30S++ VH80"
M30SPlusPlusVH90 = "M30S++ VH90"
M30SPlusPlusVH100 = "M30S++ VH100"
M30SPlusPlusVJ20 = "M30S++ VJ20"
M30SPlusPlusVJ30 = "M30S++ VJ30"
M31V10 = "M31 V10"
M31V20 = "M31 V20"
M31HV10 = "M31H V10"
M31HV40 = "M31H V40"
M31LV10 = "M30L V10"
M31SV10 = "M31S V10"
M31SV20 = "M31S V20"
M31SV30 = "M31S V30"
M31SV40 = "M31S V40"
M31SV50 = "M31S V50"
M31SV60 = "M31S V60"
M31SV70 = "M31S V70"
M31SV80 = "M31S V80"
M31SV90 = "M31S V90"
M31SVE10 = "M31S VE10"
M31SVE20 = "M31S VE20"
M31SVE30 = "M31S VE30"
M31SEV10 = "M31SE V10"
M31SEV20 = "M31SE V20"
M31SEV30 = "M31SE V30"
M31SPlusV10 = "M31S+ V10"
M31SPlusV20 = "M31S+ V20"
M31SPlusV30 = "M31S+ V30"
M31SPlusV40 = "M31S+ V40"
M31SPlusV50 = "M31S+ V50"
M31SPlusV60 = "M31S+ V60"
M31SPlusV80 = "M31S+ V80"
M31SPlusV90 = "M31S+ V90"
M31SPlusV100 = "M31S+ V100"
M31SPlusVE10 = "M31S+ VE10"
M31SPlusVE20 = "M31S+ VE20"
M31SPlusVE30 = "M31S+ VE30"
M31SPlusVE40 = "M31S+ VE40"
M31SPlusVE50 = "M31S+ VE50"
M31SPlusVE60 = "M31S+ VE60"
M31SPlusVE80 = "M31S+ VE80"
M31SPlusVF20 = "M31S+ VF20"
M31SPlusVF30 = "M31S+ VF30"
M31SPlusVG20 = "M31S+ VG20"
M31SPlusVG30 = "M31S+ VG30"
M32V10 = "M32 V10"
M32V20 = "M32 V20"
M32S = "M32S"
M33V10 = "M33 V10"
M33V20 = "M33 V20"
M33V30 = "M33 V30"
M33SVG30 = "M33S VG30"
M33SPlusVG20 = "M33S+ VG20"
M33SPlusVH20 = "M33S+ VH20"
M33SPlusVH30 = "M33S+ VH30"
M33SPlusPlusVH20 = "M33S++ VH20"
M33SPlusPlusVH30 = "M33S++ VH30"
M33SPlusPlusVG40 = "M33S++ VG40"
M34SPlusVE10 = "M34S+ VE10"
M36SVE10 = "M36S VE10"
M36SPlusVG30 = "M36S+ VG30"
M36SPlusPlusVH30 = "M36S++ VH30"
M39V10 = "M39 V10"
M39V20 = "M39 V20"
M39V30 = "M39 V30"
M50VE30 = "M50 VE30"
M50VG30 = "M50 VG30"
M50VH10 = "M50 VH10"
M50VH20 = "M50 VH20"
M50VH30 = "M50 VH30"
M50VH40 = "M50 VH40"
M50VH50 = "M50 VH50"
M50VH60 = "M50 VH60"
M50VH70 = "M50 VH70"
M50VH80 = "M50 VH80"
M50VJ10 = "M50 VJ10"
M50VJ20 = "M50 VJ20"
M50VJ30 = "M50 VJ30"
M50SVJ10 = "M50S VJ10"
M50SVJ20 = "M50S VJ20"
M50SVJ30 = "M50S VJ30"
M50SVH10 = "M50S VH10"
M50SVH20 = "M50S VH20"
M50SVH30 = "M50S VH30"
M50SVH40 = "M50S VH40"
M50SVH50 = "M50S VH50"
M50SPlusVH30 = "M50S+ VH30"
M50SPlusVH40 = "M50S+ VH40"
M50SPlusVJ30 = "M50S+ VJ30"
M50SPlusVK20 = "M50S+ VK20"
M50SPlusPlusVK10 = "M50S++ VK10"
M50SPlusPlusVK20 = "M50S++ VK20"
M50SPlusPlusVK30 = "M50S++ VK30"
M53VH30 = "M53 VH30"
M53SVH30 = "M53S VH30"
M53SVJ40 = "M53S VJ40"
M53SPlusVJ30 = "M53S+ VJ30"
M53SPlusPlusVK10 = "M53S++ VK10"
M56VH30 = "M56 VH30"
M56SVH30 = "M56S VH30"
M56SPlusVJ30 = "M56S+ VJ30"
M59VH30 = "M59 VH30"
M60VK10 = "M60 VK10"
M60VK20 = "M60 VK20"
M60VK30 = "M60 VK30"
M60VK40 = "M60 VK40"
M60SVK10 = "M60S VK10"
M60SVK20 = "M60S VK20"
M60SVK30 = "M60S VK30"
M60SVK40 = "M60S VK40"
M63VK10 = "M63 VK10"
M63VK20 = "M63 VK20"
M63VK30 = "M63 VK30"
M63SVK10 = "M63S VK10"
M63SVK20 = "M63S VK20"
M63SVK30 = "M63S VK30"
M66VK20 = "M66 VK20"
M66VK30 = "M66 VK30"
M66SVK20 = "M66S VK20"
M66SVK30 = "M66S VK30"
M66SVK40 = "M66S VK40"
def __str__(self):
return self.value
class AvalonminerModels(str, Enum):
Avalon721 = "Avalon 721"
Avalon741 = "Avalon 741"
Avalon761 = "Avalon 761"
Avalon821 = "Avalon 821"
Avalon841 = "Avalon 841"
Avalon851 = "Avalon 851"
Avalon921 = "Avalon 921"
Avalon1026 = "Avalon 1026"
Avalon1047 = "Avalon 1047"
Avalon1066 = "Avalon 1066"
Avalon1166Pro = "Avalon 1166 Pro"
Avalon1246 = "Avalon 1246"
def __str__(self):
return self.value
class InnosiliconModels(str, Enum):
T3HPlus = "T3H+"
A10X = "A10X"
def __str__(self):
return self.value
class GoldshellModels(str, Enum):
CK5 = "CK5"
HS5 = "HS5"
KD5 = "KD5"
KDMax = "KD Max"
KDBoxII = "KD Box II"
KDBoxPro = "KD Box Pro"
def __str__(self):
return self.value
class ePICModels(str, Enum):
BM520i = "BlockMiner 520i"
BM720i = "BlockMiner 720i"
def __str__(self):
return self.value
class AuradineModels(str, Enum):
AT1500 = "AT1500"
AT2860 = "AT2860"
AT2880 = "AT2880"
AI2500 = "AI2500"
AI3680 = "AI3680"
AD2500 = "AD2500"
AD3500 = "AD3500"
def __str__(self):
return self.value
class MinerModel:
ANTMINER = AntminerModels
WHATSMINER = WhatsminerModels
AVALONMINER = AvalonminerModels
INNOSILICON = InnosiliconModels
GOLDSHELL = GoldshellModels
AURADINE = AuradineModels
EPIC = ePICModels

View File

@@ -20,7 +20,16 @@ from typing import List, Union
from pyasic.errors import APIError
from pyasic.miners import AnyMiner
from pyasic.miners.backends import AntminerModern, BOSMiner, BTMiner
from pyasic.miners.models import S9, S17, T17, S17e, S17Plus, S17Pro, T17e, T17Plus
from pyasic.miners.device.models import (
S9,
S17,
T17,
S17e,
S17Plus,
S17Pro,
T17e,
T17Plus,
)
FAN_USAGE = 50 # 50 W per fan

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import AntminerOld
from pyasic.miners.models import S17, S17e, S17Plus, S17Pro
from pyasic.miners.device.models import S17, S17e, S17Plus, S17Pro
class BMMinerS17(AntminerOld, S17):

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import AntminerOld
from pyasic.miners.models import T17, T17e, T17Plus
from pyasic.miners.device.models import T17, T17e, T17Plus
class BMMinerT17(AntminerOld, T17):

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import AntminerModern
from pyasic.miners.models import (
from pyasic.miners.device.models import (
S19,
S19L,
S19XP,
@@ -26,12 +26,12 @@ from pyasic.miners.models import (
S19j,
S19jNoPIC,
S19jPro,
S19KPro,
S19Plus,
S19Pro,
S19ProHydro,
S19ProPlus,
S19ProPlusHydro,
S19KPro,
)

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import AntminerModern
from pyasic.miners.models import T19
from pyasic.miners.device.models import T19
class BMMinerT19(AntminerModern, T19):

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import AntminerModern
from pyasic.miners.models import S21
from pyasic.miners.device.models import S21
class BMMinerS21(AntminerModern, S21):

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import AntminerModern
from pyasic.miners.models import T21
from pyasic.miners.device.models import T21
class BMMinerT21(AntminerModern, T21):

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import AntminerModern
from pyasic.miners.models import HS3
from pyasic.miners.device.models import HS3
class BMMinerHS3(AntminerModern, HS3):

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import AntminerOld
from pyasic.miners.models import L3Plus
from pyasic.miners.device.models import L3Plus
class BMMinerL3Plus(AntminerOld, L3Plus):

View File

@@ -14,7 +14,7 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
from pyasic.miners.backends import AntminerModern
from pyasic.miners.models import L7
from pyasic.miners.device.models import L7
class BMMinerL7(AntminerModern, L7):

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import AntminerModern
from pyasic.miners.models import E9Pro
from pyasic.miners.device.models import E9Pro
class BMMinerE9Pro(AntminerModern, E9Pro):

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import BMMiner
from pyasic.miners.models import S9, S9i, S9j
from pyasic.miners.device.models import S9, S9i, S9j
class BMMinerS9(BMMiner, S9):

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import BMMiner
from pyasic.miners.models import T9
from pyasic.miners.device.models import T9
class BMMinerT9(BMMiner, T9):

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import BOSMiner
from pyasic.miners.models import S17, S17e, S17Plus, S17Pro
from pyasic.miners.device.models import S17, S17e, S17Plus, S17Pro
class BOSMinerS17(BOSMiner, S17):

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import BOSMiner
from pyasic.miners.models import T17, T17e, T17Plus
from pyasic.miners.device.models import T17, T17e, T17Plus
class BOSMinerT17(BOSMiner, T17):

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import BOSer
from pyasic.miners.models import (
from pyasic.miners.device.models import (
S19,
S19XP,
S19a,

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import BOSer
from pyasic.miners.models import T19
from pyasic.miners.device.models import T19
class BOSMinerT19(BOSer, T19):

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import BOSer
from pyasic.miners.models import S21
from pyasic.miners.device.models import S21
class BOSMinerS21(BOSer, S21):

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import BOSMiner
from pyasic.miners.models import S9
from pyasic.miners.device.models import S9
class BOSMinerS9(BOSMiner, S9):

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import AntminerOld
from pyasic.miners.models import Z15
from pyasic.miners.device.models import Z15
class CGMinerZ15(AntminerOld, Z15):

View File

@@ -14,7 +14,7 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
from pyasic.miners.backends import AntminerOld
from pyasic.miners.models import D3
from pyasic.miners.device.models import D3
class CGMinerD3(AntminerOld, D3):

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import AntminerOld
from pyasic.miners.models import DR5
from pyasic.miners.device.models import DR5
class CGMinerDR5(AntminerOld, DR5):

View File

@@ -15,7 +15,15 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import ePIC
from pyasic.miners.models import S19, S19XP, S19j, S19jPro, S19jProPlus, S19kPro, S19Pro
from pyasic.miners.device.models import (
S19,
S19XP,
S19j,
S19jPro,
S19jProPlus,
S19kPro,
S19Pro,
)
class ePICS19(ePIC, S19):

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import ePIC
from pyasic.miners.models import S21
from pyasic.miners.device.models import S21
class ePICS21(ePIC, S21):

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import ePIC
from pyasic.miners.models import T21
from pyasic.miners.device.models import T21
class ePICT21(ePIC, T21):

View File

@@ -18,11 +18,11 @@ from typing import List, Optional
import asyncssh
from pyasic.data import HashBoard
from pyasic.data import AlgoHashRate, HashBoard, HashUnit
from pyasic.errors import APIError
from pyasic.miners.backends import Hiveon
from pyasic.miners.data import DataFunction, DataLocations, DataOptions, RPCAPICommand
from pyasic.miners.models import T9
from pyasic.miners.device.models import T9
HIVEON_T9_DATA_LOC = DataLocations(
**{
@@ -121,7 +121,9 @@ class HiveonT9(Hiveon, T9):
chips += rpc_stats["STATS"][1][f"chain_acn{chipset}"]
except (KeyError, IndexError):
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
return hashboards

View File

@@ -15,7 +15,14 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import LUXMiner
from pyasic.miners.models import S19, S19XP, S19jPro, S19jProPlus, S19kPro, S19Pro
from pyasic.miners.device.models import (
S19,
S19XP,
S19jPro,
S19jProPlus,
S19kPro,
S19Pro,
)
class LUXMinerS19(LUXMiner, S19):

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import LUXMiner
from pyasic.miners.models import T19
from pyasic.miners.device.models import T19
class LUXMinerT19(LUXMiner, T19):

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import LUXMiner
from pyasic.miners.models import S21
from pyasic.miners.device.models import S21
class LUXMinerS21(LUXMiner, S21):

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import LUXMiner
from pyasic.miners.models import S9
from pyasic.miners.device.models import S9
class LUXMinerS9(LUXMiner, S9):

View File

@@ -15,7 +15,15 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import MaraMiner
from pyasic.miners.models import S19, S19XP, S19j, S19jNoPIC, S19jPro, S19KPro, S19Pro
from pyasic.miners.device.models import (
S19,
S19XP,
S19j,
S19jNoPIC,
S19jPro,
S19KPro,
S19Pro,
)
class MaraS19(MaraMiner, S19):

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import MaraMiner
from pyasic.miners.models import S21
from pyasic.miners.device.models import S21
class MaraS21(MaraMiner, S21):

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import MaraMiner
from pyasic.miners.models import T21
from pyasic.miners.device.models import T21
class MaraT21(MaraMiner, T21):

View File

@@ -14,7 +14,7 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
from pyasic.miners.backends import VNish
from pyasic.miners.models import S17Plus, S17Pro
from pyasic.miners.device.models import S17Plus, S17Pro
class VNishS17Plus(VNish, S17Plus):

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import VNish
from pyasic.miners.models import (
from pyasic.miners.device.models import (
S19,
S19XP,
S19a,

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import VNish
from pyasic.miners.models import T19
from pyasic.miners.device.models import T19
class VNishT19(VNish, T19):

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import VNish
from pyasic.miners.models import L3Plus
from pyasic.miners.device.models import L3Plus
class VnishL3Plus(VNish, L3Plus):

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import VNish
from pyasic.miners.models import L7
from pyasic.miners.device.models import L7
class VnishL7(VNish, L7):

View File

@@ -1,5 +1,5 @@
from pyasic.miners.backends import Auradine
from pyasic.miners.models import AuradineAT1500
from pyasic.miners.device.models import AuradineAT1500
class AuradineFluxAT1500(AuradineAT1500, Auradine):

View File

@@ -1,5 +1,5 @@
from pyasic.miners.backends import Auradine
from pyasic.miners.models import AuradineAT2860, AuradineAT2880
from pyasic.miners.device.models import AuradineAT2860, AuradineAT2880
class AuradineFluxAT2860(AuradineAT2860, Auradine):

View File

@@ -1,5 +1,5 @@
from pyasic.miners.backends import Auradine
from pyasic.miners.models import AuradineAI2500
from pyasic.miners.device.models import AuradineAI2500
class AuradineFluxAI2500(AuradineAI2500, Auradine):

View File

@@ -1,5 +1,5 @@
from pyasic.miners.backends import Auradine
from pyasic.miners.models import AuradineAI3680
from pyasic.miners.device.models import AuradineAI3680
class AuradineFluxAI3680(AuradineAI3680, Auradine):

View File

@@ -1,5 +1,5 @@
from pyasic.miners.backends import Auradine
from pyasic.miners.models import AuradineAD2500
from pyasic.miners.device.models import AuradineAD2500
class AuradineFluxAD2500(AuradineAD2500, Auradine):

View File

@@ -1,5 +1,5 @@
from pyasic.miners.backends import Auradine
from pyasic.miners.models import AuradineAD3500
from pyasic.miners.device.models import AuradineAD3500
class AuradineFluxAD3500(AuradineAD3500, Auradine):

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import AvalonMiner
from pyasic.miners.models import Avalon1026
from pyasic.miners.device.models import Avalon1026
class CGMinerAvalon1026(AvalonMiner, Avalon1026):

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import AvalonMiner
from pyasic.miners.models import Avalon1047
from pyasic.miners.device.models import Avalon1047
class CGMinerAvalon1047(AvalonMiner, Avalon1047):

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import AvalonMiner
from pyasic.miners.models import Avalon1066
from pyasic.miners.device.models import Avalon1066
class CGMinerAvalon1066(AvalonMiner, Avalon1066):

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import AvalonMiner
from pyasic.miners.models import Avalon1166Pro
from pyasic.miners.device.models import Avalon1166Pro
class CGMinerAvalon1166Pro(AvalonMiner, Avalon1166Pro):

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import AvalonMiner
from pyasic.miners.models import Avalon1246
from pyasic.miners.device.models import Avalon1246
class CGMinerAvalon1246(AvalonMiner, Avalon1246):

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import AvalonMiner
from pyasic.miners.models import Avalon721
from pyasic.miners.device.models import Avalon721
class CGMinerAvalon721(AvalonMiner, Avalon721):

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import AvalonMiner
from pyasic.miners.models import Avalon741
from pyasic.miners.device.models import Avalon741
class CGMinerAvalon741(AvalonMiner, Avalon741):

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import AvalonMiner
from pyasic.miners.models import Avalon761
from pyasic.miners.device.models import Avalon761
class CGMinerAvalon761(AvalonMiner, Avalon761):

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import AvalonMiner
from pyasic.miners.models import Avalon821
from pyasic.miners.device.models import Avalon821
class CGMinerAvalon821(AvalonMiner, Avalon821):

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import AvalonMiner
from pyasic.miners.models import Avalon841
from pyasic.miners.device.models import Avalon841
class CGMinerAvalon841(AvalonMiner, Avalon841):

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import AvalonMiner
from pyasic.miners.models import Avalon851
from pyasic.miners.device.models import Avalon851
class CGMinerAvalon851(AvalonMiner, Avalon851):

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import AvalonMiner
from pyasic.miners.models import Avalon921
from pyasic.miners.device.models import Avalon921
class CGMinerAvalon921(AvalonMiner, Avalon921):

View File

@@ -17,12 +17,11 @@
from typing import List, Optional, Union
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.errors import APIError
from pyasic.miners.backends.bmminer import BMMiner
from pyasic.miners.backends.cgminer import CGMiner
from pyasic.miners.base import BaseMiner
from pyasic.miners.data import (
DataFunction,
DataLocations,
@@ -219,9 +218,9 @@ class AntminerModern(BMMiner):
if rpc_stats is not None:
try:
for board in rpc_stats["STATS"][0]["chain"]:
hashboards[board["index"]].hashrate = round(
board["rate_real"] / 1000, 2
)
hashboards[board["index"]].hashrate = AlgoHashRate.SHA256(
board["rate_real"], HashUnit.SHA256.GH
).into(self.algo.unit.default)
hashboards[board["index"]].chips = board["asic_num"]
board_temp_data = list(
filter(lambda x: not x == 0, board["temp_pcb"])
@@ -274,12 +273,9 @@ class AntminerModern(BMMiner):
rate_unit = rpc_stats["STATS"][1]["rate_unit"]
except KeyError:
rate_unit = "GH"
if rate_unit == "GH":
return round(expected_rate / 1000, 2)
if rate_unit == "MH":
return round(expected_rate / 1000000, 2)
else:
return round(expected_rate, 2)
return AlgoHashRate.SHA256(
expected_rate, HashUnit.SHA256.from_str(rate_unit)
).int(self.algo.unit.default)
except LookupError:
pass
@@ -553,7 +549,9 @@ class AntminerOld(CGMiner):
hashrate = boards[1].get(f"chain_rate{i}")
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}")
if chips:

View File

@@ -18,9 +18,8 @@ from enum import Enum
from typing import List, Optional
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.miners.base import BaseMiner
from pyasic.miners.data import (
DataFunction,
DataLocations,
@@ -28,6 +27,7 @@ from pyasic.miners.data import (
RPCAPICommand,
WebAPICommand,
)
from pyasic.miners.device.firmware import StockFirmware
from pyasic.rpc.gcminer import GCMinerRPCAPI
from pyasic.web.auradine import AuradineWebAPI
@@ -113,7 +113,7 @@ class AuradineLEDCodes(Enum):
return self.value
class Auradine(BaseMiner):
class Auradine(StockFirmware):
"""Base handler for Auradine miners"""
_rpc_cls = GCMinerRPCAPI
@@ -245,9 +245,9 @@ class Auradine(BaseMiner):
if rpc_summary is not None:
try:
return round(
float(float(rpc_summary["SUMMARY"][0]["MHS 5s"]) / 1000000), 2
)
return AlgoHashRate.SHA256(
rpc_summary["SUMMARY"][0]["MHS 5s"], HashUnit.SHA256.MH
).into(self.algo.unit.default)
except (LookupError, ValueError, TypeError):
pass
@@ -274,9 +274,9 @@ class Auradine(BaseMiner):
try:
for board in rpc_devs["DEVS"]:
b_id = board["ID"] - 1
hashboards[b_id].hashrate = round(
float(float(board["MHS 5s"]) / 1000000), 2
)
hashboards[b_id].hashrate = AlgoHashRate.SHA256(
board["MHS 5s"], HashUnit.SHA256.MH
).into(self.algo.unit.default)
hashboards[b_id].temp = round(float(float(board["Temperature"])), 2)
hashboards[b_id].missing = False
except LookupError:

View File

@@ -17,7 +17,7 @@
import re
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.miners.backends.cgminer import CGMiner
from pyasic.miners.data import DataFunction, DataLocations, DataOptions, RPCAPICommand
@@ -182,7 +182,9 @@ class AvalonMiner(CGMiner):
if rpc_devs is not None:
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):
pass
@@ -213,7 +215,9 @@ class AvalonMiner(CGMiner):
try:
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:
pass
@@ -245,7 +249,9 @@ class AvalonMiner(CGMiner):
try:
unparsed_stats = rpc_stats["STATS"][0]["MM ID0"]
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):
pass

View File

@@ -17,10 +17,10 @@
from typing import List, Optional
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.miners.base import BaseMiner
from pyasic.miners.data import DataFunction, DataLocations, DataOptions, RPCAPICommand
from pyasic.miners.device.firmware import StockFirmware
from pyasic.rpc.bfgminer import BFGMinerRPCAPI
BFGMINER_DATA_LOC = DataLocations(
@@ -53,7 +53,7 @@ BFGMINER_DATA_LOC = DataLocations(
)
class BFGMiner(BaseMiner):
class BFGMiner(StockFirmware):
"""Base handler for BFGMiner based miners."""
_rpc_cls = BFGMinerRPCAPI
@@ -115,7 +115,9 @@ class BFGMiner(BaseMiner):
if rpc_summary is not None:
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):
pass
@@ -159,7 +161,9 @@ class BFGMiner(BaseMiner):
hashrate = boards[1].get(f"chain_rate{i}")
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}")
if chips:
@@ -218,11 +222,8 @@ class BFGMiner(BaseMiner):
rate_unit = rpc_stats["STATS"][1]["rate_unit"]
except KeyError:
rate_unit = "GH"
if rate_unit == "GH":
return round(expected_rate / 1000, 2)
if rate_unit == "MH":
return round(expected_rate / 1000000, 2)
else:
return round(expected_rate, 2)
return AlgoHashRate.SHA256(
expected_rate, HashUnit.SHA256.from_str(rate_unit)
).int(self.algo.unit.default)
except LookupError:
pass

View File

@@ -17,10 +17,10 @@
from typing import List, Optional
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.miners.base import BaseMiner
from pyasic.miners.data import DataFunction, DataLocations, DataOptions, RPCAPICommand
from pyasic.miners.device.firmware import StockFirmware
from pyasic.rpc.bmminer import BMMinerRPCAPI
BMMINER_DATA_LOC = DataLocations(
@@ -57,7 +57,7 @@ BMMINER_DATA_LOC = DataLocations(
)
class BMMiner(BaseMiner):
class BMMiner(StockFirmware):
"""Base handler for BMMiner based miners."""
_rpc_cls = BMMinerRPCAPI
@@ -119,7 +119,9 @@ class BMMiner(BaseMiner):
if rpc_summary is not None:
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):
pass
@@ -176,7 +178,9 @@ class BMMiner(BaseMiner):
hashrate = boards[1].get(f"chain_rate{i}")
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}")
if chips:
@@ -234,12 +238,9 @@ class BMMiner(BaseMiner):
rate_unit = rpc_stats["STATS"][1]["rate_unit"]
except KeyError:
rate_unit = "GH"
if rate_unit == "GH":
return round(expected_rate / 1000, 2)
if rate_unit == "MH":
return round(expected_rate / 1000000, 2)
else:
return round(expected_rate, 2)
return AlgoHashRate.SHA256(
expected_rate, HashUnit.SHA256.from_str(rate_unit)
).int(self.algo.unit.default)
except LookupError:
pass

View File

@@ -21,10 +21,9 @@ import toml
from pyasic.config import MinerConfig
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.errors import APIError
from pyasic.miners.base import BaseMiner
from pyasic.miners.data import (
DataFunction,
DataLocations,
@@ -32,6 +31,7 @@ from pyasic.miners.data import (
RPCAPICommand,
WebAPICommand,
)
from pyasic.miners.device.firmware import BraiinsOSFirmware
from pyasic.rpc.bosminer import BOSMinerRPCAPI
from pyasic.ssh.braiins_os import BOSMinerSSH
from pyasic.web.braiins_os import BOSerWebAPI, BOSMinerWebAPI
@@ -95,7 +95,7 @@ BOSMINER_DATA_LOC = DataLocations(
)
class BOSMiner(BaseMiner):
class BOSMiner(BraiinsOSFirmware):
"""Handler for old versions of BraiinsOS+ (pre-gRPC)"""
_rpc_cls = BOSMinerRPCAPI
@@ -105,8 +105,6 @@ class BOSMiner(BaseMiner):
_ssh_cls = BOSMinerSSH
ssh: BOSMinerSSH
firmware = "BOS+"
data_locations = BOSMINER_DATA_LOC
supports_shutdown = True
@@ -352,7 +350,9 @@ class BOSMiner(BaseMiner):
if rpc_summary is not None:
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):
pass
@@ -422,8 +422,9 @@ class BOSMiner(BaseMiner):
for board in rpc_devs["DEVS"]:
_id = board["ID"] - offset
hashrate = round(float(board["MHS 1m"] / 1000000), 2)
hashboards[_id].hashrate = hashrate
hashboards[_id].hashrate = AlgoHashRate.SHA256(
board["MHS 1m"], HashUnit.SHA256.MH
).into(self.algo.unit.default)
except (IndexError, KeyError):
pass
@@ -531,11 +532,12 @@ class BOSMiner(BaseMiner):
expected_hashrate = round(float(board["Nominal MHS"] / 1000000), 2)
if expected_hashrate:
hr_list.append(expected_hashrate)
if len(hr_list) == 0:
return 0
return AlgoHashRate.SHA256(0)
else:
return round(
(sum(hr_list) / len(hr_list)) * self.expected_hashboards, 2
return AlgoHashRate.SHA256(
(sum(hr_list) / len(hr_list)) * self.expected_hashboards
)
except (IndexError, KeyError):
pass
@@ -635,7 +637,7 @@ BOSER_DATA_LOC = DataLocations(
)
class BOSer(BaseMiner):
class BOSer(BraiinsOSFirmware):
"""Handler for new versions of BraiinsOS+ (post-gRPC)"""
_rpc_cls = BOSMinerRPCAPI
@@ -643,8 +645,6 @@ class BOSer(BaseMiner):
_web_cls = BOSerWebAPI
web: BOSerWebAPI
firmware = "BOS+"
data_locations = BOSER_DATA_LOC
supports_autotuning = True
@@ -788,7 +788,9 @@ class BOSer(BaseMiner):
if rpc_summary is not None:
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):
pass
@@ -803,7 +805,10 @@ class BOSer(BaseMiner):
if grpc_miner_details is not None:
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:
pass
@@ -832,13 +837,12 @@ class BOSer(BaseMiner):
]
if board.get("stats") is not None:
if not board["stats"]["realHashrate"]["last5S"] == {}:
hashboards[idx].hashrate = round(
hashboards[idx].hashrate = AlgoHashRate.SHA256(
board["stats"]["realHashrate"]["last5S"][
"gigahashPerSecond"
]
/ 1000,
2,
)
],
HashUnit.SHA256.GH,
).into(self.algo.unit.default)
hashboards[idx].missing = False
return hashboards
@@ -861,7 +865,9 @@ class BOSer(BaseMiner):
) -> Optional[int]:
if grpc_active_performance_mode is None:
try:
grpc_active_performance_mode = self.web.get_active_performance_mode()
grpc_active_performance_mode = (
await self.web.get_active_performance_mode()
)
except APIError:
pass

View File

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

View File

@@ -17,9 +17,10 @@
from typing import Optional
from pyasic.config import MinerConfig
from pyasic.data import AlgoHashRate, HashUnit
from pyasic.errors import APIError
from pyasic.miners.base import BaseMiner
from pyasic.miners.data import DataFunction, DataLocations, DataOptions, RPCAPICommand
from pyasic.miners.device.firmware import StockFirmware
from pyasic.rpc.cgminer import CGMinerRPCAPI
CGMINER_DATA_LOC = DataLocations(
@@ -56,7 +57,7 @@ CGMINER_DATA_LOC = DataLocations(
)
class CGMiner(BaseMiner):
class CGMiner(StockFirmware):
"""Base handler for CGMiner based miners"""
_rpc_cls = CGMinerRPCAPI
@@ -117,9 +118,9 @@ class CGMiner(BaseMiner):
if rpc_summary is not None:
try:
return round(
float(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):
pass

View File

@@ -17,12 +17,12 @@
from typing import List, Optional
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.errors import APIError
from pyasic.logger import logger
from pyasic.miners.base import BaseMiner
from pyasic.miners.data import DataFunction, DataLocations, DataOptions, WebAPICommand
from pyasic.miners.device.firmware import ePICFirmware
from pyasic.web.epic import ePICWebAPI
EPIC_DATA_LOC = DataLocations(
@@ -58,6 +58,10 @@ EPIC_DATA_LOC = DataLocations(
"_get_wattage",
[WebAPICommand("web_summary", "summary")],
),
str(DataOptions.VOLTAGE): DataFunction(
"_get_voltage",
[WebAPICommand("web_summary", "summary")],
),
str(DataOptions.FANS): DataFunction(
"_get_fans",
[WebAPICommand("web_summary", "summary")],
@@ -82,14 +86,12 @@ EPIC_DATA_LOC = DataLocations(
)
class ePIC(BaseMiner):
class ePIC(ePICFirmware):
"""Handler for miners with the ePIC board"""
_web_cls = ePICWebAPI
web: ePICWebAPI
firmware = "ePIC"
data_locations = EPIC_DATA_LOC
supports_shutdown = True
@@ -119,6 +121,7 @@ class ePIC(BaseMiner):
# Temps
if not conf.get("temps", {}) == {}:
await self.web.set_shutdown_temp(conf["temps"]["shutdown"])
await self.web.set_critical_temp(conf["temps"]["critical"])
# Fans
# set with sub-keys instead of conf["fans"] because sometimes both can be set
if not conf["fans"].get("Manual", {}) == {}:
@@ -129,7 +132,7 @@ class ePIC(BaseMiner):
# Mining Mode -- Need to handle that you may not be able to change while miner is tuning
if conf["ptune"].get("enabled", True):
await self.web.set_ptune_enable(True)
await self.web.set_ptune_algo(**conf["ptune"])
await self.web.set_ptune_algo(conf["ptune"])
## Pools
await self.web.set_pools(conf["pools"])
@@ -216,6 +219,20 @@ class ePIC(BaseMiner):
except KeyError:
pass
async def _get_voltage(self, web_summary: dict = None) -> Optional[float]:
if web_summary is None:
try:
web_summary = await self.web.summary()
except APIError:
pass
if web_summary is not None:
try:
voltage = web_summary["Power Supply Stats"]["Output Voltage"]
return voltage
except KeyError:
pass
async def _get_hashrate(self, web_summary: dict = None) -> Optional[float]:
if web_summary is None:
try:
@@ -229,7 +246,9 @@ class ePIC(BaseMiner):
if web_summary["HBs"] is not None:
for hb in web_summary["HBs"]:
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):
pass
@@ -251,7 +270,9 @@ class ePIC(BaseMiner):
ideal = hb["Hashrate"][1] / 100
hashrate += hb["Hashrate"][0] / ideal
return round(float(float(hashrate / 1000000)), 2)
return AlgoHashRate.SHA256(hashrate, HashUnit.SHA256.MH).into(
self.algo.unit.default
)
except (LookupError, ValueError, TypeError):
pass
@@ -296,7 +317,7 @@ class ePIC(BaseMiner):
except APIError:
pass
if web_capabilities is not None:
if web_capabilities is None:
try:
web_capabilities = await self.web.capabilities()
except APIError:
@@ -306,16 +327,29 @@ class ePIC(BaseMiner):
HashBoard(slot=i, expected_chips=self.expected_chips)
for i in range(self.expected_hashboards)
]
if web_summary.get("HBs") is not None:
for hb in web_summary["HBs"]:
num_of_chips = web_capabilities["Performance Estimator"]["Chip Count"]
hashrate = hb["Hashrate"][0]
# Update the Hashboard object
hb_list[hb["Index"]].missing = False
hb_list[hb["Index"]].hashrate = round(hashrate / 1000000, 2)
hb_list[hb["Index"]].chips = num_of_chips
hb_list[hb["Index"]].temp = hb["Temperature"]
return hb_list
if web_summary is not None and web_capabilities is not None:
if web_summary.get("HBs") is not None:
for hb in web_summary["HBs"]:
if web_capabilities.get("Performance Estimator") is not None:
num_of_chips = web_capabilities["Performance Estimator"][
"Chip Count"
]
else:
num_of_chips = self.expected_chips
if web_capabilities.get("Board Serial Numbers") is not None:
if hb["Index"] < len(web_capabilities["Board Serial Numbers"]):
hb_list[hb["Index"]].serial_number = web_capabilities[
"Board Serial Numbers"
][hb["Index"]]
hashrate = hb["Hashrate"][0]
# Update the Hashboard object
hb_list[hb["Index"]].missing = False
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"]].temp = hb["Temperature"]
return hb_list
async def _is_mining(self, web_summary, *args, **kwargs) -> Optional[bool]:
if web_summary is None:

View File

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

View File

@@ -15,7 +15,8 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import BMMiner
from pyasic.miners.device.firmware import HiveonFirmware
class Hiveon(BMMiner):
firmware = "Hive"
class Hiveon(BMMiner, HiveonFirmware):
pass

View File

@@ -16,7 +16,7 @@
from typing import List, Optional
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.innosilicon import InnosiliconError
from pyasic.errors import APIError
@@ -182,20 +182,21 @@ class Innosilicon(CGMiner):
if web_get_all is not None:
try:
if "Hash Rate H" in web_get_all["total_hash"].keys():
return round(
float(web_get_all["total_hash"]["Hash Rate H"] / 1000000000000),
2,
)
return AlgoHashRate.SHA256(
web_get_all["total_hash"]["Hash Rate H"], HashUnit.SHA256.H
).into(self.algo.unit.default)
elif "Hash Rate" in web_get_all["total_hash"].keys():
return round(
float(web_get_all["total_hash"]["Hash Rate"] / 1000000), 5
)
return AlgoHashRate.SHA256(
web_get_all["total_hash"]["Hash Rate"], HashUnit.SHA256.MH
).into(self.algo.unit.default)
except KeyError:
pass
if rpc_summary is not None:
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):
pass
@@ -247,9 +248,9 @@ class Innosilicon(CGMiner):
hashrate = board.get("Hash Rate H")
if hashrate:
hashboards[idx].hashrate = round(
hashrate / 1000000000000, 2
)
hashboards[idx].hashrate = AlgoHashRate.SHA256(
hashrate, HashUnit.SHA256.H
).into(self.algo.unit.default)
chip_temp = board.get("Temp max")
if chip_temp:

View File

@@ -16,10 +16,10 @@
from typing import List, Optional
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.miners.base import BaseMiner
from pyasic.miners.data import DataFunction, DataLocations, DataOptions, RPCAPICommand
from pyasic.miners.device.firmware import LuxOSFirmware
from pyasic.rpc.luxminer import LUXMinerRPCAPI
LUXMINER_DATA_LOC = DataLocations(
@@ -55,14 +55,12 @@ LUXMINER_DATA_LOC = DataLocations(
)
class LUXMiner(BaseMiner):
class LUXMiner(LuxOSFirmware):
"""Handler for LuxOS miners"""
_rpc_cls = LUXMinerRPCAPI
rpc: LUXMinerRPCAPI
firmware = "LuxOS"
data_locations = LUXMINER_DATA_LOC
async def _get_session(self) -> Optional[str]:
@@ -173,7 +171,9 @@ class LUXMiner(BaseMiner):
if rpc_summary is not None:
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):
pass
@@ -217,7 +217,9 @@ class LUXMiner(BaseMiner):
hashrate = boards[1].get(f"chain_rate{i}")
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}")
if chips:
@@ -275,12 +277,9 @@ class LUXMiner(BaseMiner):
rate_unit = rpc_stats["STATS"][1]["rate_unit"]
except KeyError:
rate_unit = "GH"
if rate_unit == "GH":
return round(expected_rate / 1000, 2)
if rate_unit == "MH":
return round(expected_rate / 1000000, 2)
else:
return round(expected_rate, 2)
return AlgoHashRate.SHA256(
expected_rate, HashUnit.SHA256.from_str(rate_unit)
).int(self.algo.unit.default)
except LookupError:
pass

View File

@@ -2,10 +2,10 @@ from typing import List, Optional
from pyasic import MinerConfig
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.miners.base import BaseMiner
from pyasic.miners.data import DataFunction, DataLocations, DataOptions, WebAPICommand
from pyasic.miners.device.firmware import MaraFirmware
from pyasic.misc import merge_dicts
from pyasic.web.marathon import MaraWebAPI
@@ -63,14 +63,12 @@ MARA_DATA_LOC = DataLocations(
)
class MaraMiner(BaseMiner):
class MaraMiner(MaraFirmware):
_web_cls = MaraWebAPI
web: MaraWebAPI
data_locations = MARA_DATA_LOC
firmware = "MaraFW"
async def fault_light_off(self) -> bool:
res = await self.web.set_locate_miner(blinking=False)
return res.get("blinking") is False
@@ -172,7 +170,9 @@ class MaraMiner(BaseMiner):
try:
for hb in web_hashboards["hashboards"]:
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(
sum(hb["temperature_pcb"]) / len(hb["temperature_pcb"]), 2
)
@@ -234,7 +234,9 @@ class MaraMiner(BaseMiner):
if web_brief is not None:
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:
pass
@@ -278,7 +280,9 @@ class MaraMiner(BaseMiner):
if web_brief is not None:
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:
pass

View File

@@ -17,6 +17,7 @@
from typing import Optional
from pyasic import MinerConfig
from pyasic.data import AlgoHashRate, HashUnit
from pyasic.errors import APIError
from pyasic.miners.backends.bmminer import BMMiner
from pyasic.miners.data import (
@@ -26,6 +27,7 @@ from pyasic.miners.data import (
RPCAPICommand,
WebAPICommand,
)
from pyasic.miners.device.firmware import VNishFirmware
from pyasic.web.vnish import VNishWebAPI
VNISH_DATA_LOC = DataLocations(
@@ -82,7 +84,7 @@ VNISH_DATA_LOC = DataLocations(
)
class VNish(BMMiner):
class VNish(BMMiner, VNishFirmware):
"""Handler for VNish miners"""
_web_cls = VNishWebAPI
@@ -90,8 +92,6 @@ class VNish(BMMiner):
supports_shutdown = True
firmware = "VNish"
data_locations = VNISH_DATA_LOC
async def restart_backend(self) -> bool:
@@ -187,9 +187,9 @@ class VNish(BMMiner):
if rpc_summary is not None:
try:
return round(
float(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):
pass

View File

@@ -20,7 +20,12 @@ from typing import List, Optional, Protocol, Tuple, Type, TypeVar, Union
from pyasic.config import MinerConfig
from pyasic.data import Fan, HashBoard, MinerData
from pyasic.data.device import DeviceInfo
from pyasic.data.error_codes import MinerErrorData
from pyasic.device import MinerModel
from pyasic.device.algorithm import MinerAlgo
from pyasic.device.firmware import MinerFirmware
from pyasic.device.makes import MinerMake
from pyasic.errors import APIError
from pyasic.logger import logger
from pyasic.miners.data import DataLocations, DataOptions, RPCAPICommand, WebAPICommand
@@ -36,9 +41,10 @@ class MinerProtocol(Protocol):
web: _web_cls = None
ssh: _ssh_cls = None
make: str = None
raw_model: str = None
firmware: str = None
make: MinerMake = None
raw_model: MinerModel = None
firmware: MinerFirmware = None
algo = MinerAlgo.SHA256
expected_hashboards: int = 3
expected_chips: int = None
@@ -79,6 +85,12 @@ class MinerProtocol(Protocol):
model_data.append(f"({self.firmware})")
return " ".join(model_data)
@property
def device_info(self) -> DeviceInfo:
return DeviceInfo(
make=self.make, model=self.raw_model, firmware=self.firmware, algo=self.algo
)
@property
def api(self):
return self.rpc
@@ -183,6 +195,14 @@ class MinerProtocol(Protocol):
"""
return self.model
async def get_device_info(self) -> Optional[DeviceInfo]:
"""Get device information, including model, make, and firmware.
Returns:
A dataclass containing device information.
"""
return self.device_info
async def get_api_ver(self) -> Optional[str]:
"""Get the API version of the miner and is as a string.
@@ -249,6 +269,14 @@ class MinerProtocol(Protocol):
"""
return await self._get_wattage()
async def get_voltage(self) -> Optional[float]:
"""Get output voltage of the PSU as a float.
Returns:
Output voltage of the PSU as an float.
"""
return await self._get_voltage()
async def get_wattage_limit(self) -> Optional[int]:
"""Get wattage limit from the miner as an int.
@@ -337,6 +365,9 @@ class MinerProtocol(Protocol):
async def _get_wattage(self) -> Optional[int]:
pass
async def _get_voltage(self) -> Optional[float]:
pass
async def _get_wattage_limit(self) -> Optional[int]:
pass
@@ -465,14 +496,14 @@ class MinerProtocol(Protocol):
"""
data = MinerData(
ip=str(self.ip),
make=self.make,
model=self.model,
device_info=self.device_info,
expected_chips=(
self.expected_chips * self.expected_hashboards
if self.expected_chips is not None
else 0
),
expected_hashboards=self.expected_hashboards,
expected_fans=self.expected_fans,
hashboards=[
HashBoard(slot=i, expected_chips=self.expected_chips)
for i in range(self.expected_hashboards)

View File

@@ -15,8 +15,7 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import ePIC
from pyasic.miners.models import BlockMiner520i
from pyasic.miners.models import BlockMiner720i
from pyasic.miners.device.models import BlockMiner520i, BlockMiner720i
class ePICBlockMiner520i(ePIC, BlockMiner520i):

View File

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

View File

View File

@@ -0,0 +1,46 @@
# ------------------------------------------------------------------------------
# Copyright 2022 Upstream Data Inc -
# -
# Licensed under the Apache License, Version 2.0 (the "License"); -
# you may not use this file except in compliance with the License. -
# You may obtain a copy of the License at -
# -
# http://www.apache.org/licenses/LICENSE-2.0 -
# -
# Unless required by applicable law or agreed to in writing, software -
# distributed under the License is distributed on an "AS IS" BASIS, -
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -
# See the License for the specific language governing permissions and -
# limitations under the License. -
# ------------------------------------------------------------------------------
from pyasic.device.firmware import MinerFirmware
from pyasic.miners.base import BaseMiner
class StockFirmware(BaseMiner):
firmware = MinerFirmware.STOCK
class BraiinsOSFirmware(BaseMiner):
firmware = MinerFirmware.BRAIINS_OS
class VNishFirmware(BaseMiner):
firmware = MinerFirmware.VNISH
class ePICFirmware(BaseMiner):
firmware = MinerFirmware.EPIC
class HiveonFirmware(BaseMiner):
firmware = MinerFirmware.HIVEON
class LuxOSFirmware(BaseMiner):
firmware = MinerFirmware.LUXOS
class MaraFirmware(BaseMiner):
firmware = MinerFirmware.MARATHON

View File

@@ -14,32 +14,33 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
from pyasic.device.makes import MinerMake
from pyasic.miners.base import BaseMiner
class WhatsMinerMake(BaseMiner):
make = "WhatsMiner"
make = MinerMake.WHATSMINER
class AntMinerMake(BaseMiner):
make = "AntMiner"
make = MinerMake.ANTMINER
class AvalonMinerMake(BaseMiner):
make = "AvalonMiner"
make = MinerMake.AVALONMINER
class InnosiliconMake(BaseMiner):
make = "Innosilicon"
make = MinerMake.INNOSILICON
class GoldshellMake(BaseMiner):
make = "Goldshell"
make = MinerMake.GOLDSHELL
class AuradineMake(BaseMiner):
make = "Auradine"
make = MinerMake.AURADINE
class ePICMake(BaseMiner):
make = "ePIC"
make = MinerMake.EPIC

View File

@@ -17,7 +17,7 @@
from .antminer import *
from .auradine import *
from .avalonminer import *
from .epic import *
from .goldshell import *
from .innosilicon import *
from .whatsminer import *
from .epic import *

View File

@@ -13,11 +13,11 @@
# See the License for the specific language governing permissions and -
# limitations under the License. -
# ------------------------------------------------------------------------------
from pyasic.miners.makes import AntMinerMake
from pyasic.device.models import MinerModel
from pyasic.miners.device.makes import AntMinerMake
class Z15(AntMinerMake):
raw_model = "Z15"
raw_model = MinerModel.ANTMINER.Z15
expected_chips = 3
expected_fans = 2

View File

@@ -13,29 +13,33 @@
# See the License for the specific language governing permissions and -
# limitations under the License. -
# ------------------------------------------------------------------------------
from pyasic.miners.makes import AntMinerMake
from pyasic.device.models import MinerModel
from pyasic.miners.device.makes import AntMinerMake
class S17(AntMinerMake):
raw_model = "S17"
raw_model = MinerModel.ANTMINER.S17
expected_chips = 48
expected_fans = 4
class S17Plus(AntMinerMake):
raw_model = "S17+"
raw_model = MinerModel.ANTMINER.S17Plus
expected_chips = 65
expected_fans = 4
class S17Pro(AntMinerMake):
raw_model = "S17 Pro"
raw_model = MinerModel.ANTMINER.S17Pro
expected_chips = 48
expected_fans = 4
class S17e(AntMinerMake):
raw_model = "S17e"
raw_model = MinerModel.ANTMINER.S17e
expected_chips = 135
expected_fans = 4

View File

@@ -13,23 +13,26 @@
# See the License for the specific language governing permissions and -
# limitations under the License. -
# ------------------------------------------------------------------------------
from pyasic.miners.makes import AntMinerMake
from pyasic.device.models import MinerModel
from pyasic.miners.device.makes import AntMinerMake
class T17(AntMinerMake):
raw_model = "T17"
raw_model = MinerModel.ANTMINER.T17
expected_chips = 30
expected_fans = 4
class T17Plus(AntMinerMake):
raw_model = "T17+"
raw_model = MinerModel.ANTMINER.T17Plus
expected_chips = 44
expected_fans = 4
class T17e(AntMinerMake):
raw_model = "T17e"
raw_model = MinerModel.ANTMINER.T17e
expected_chips = 78
expected_fans = 4

Some files were not shown because too many files have changed in this diff Show More