Compare commits
3 Commits
v0.57.1
...
dev_scan_f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
54f0292712 | ||
|
|
46c56134f7 | ||
|
|
1c1f7f1098 |
@@ -1,3 +1,3 @@
|
|||||||
jinja2<3.1.4
|
jinja2<3.1.3
|
||||||
mkdocs
|
mkdocs
|
||||||
mkdocstrings[python]
|
mkdocstrings[python]
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ from pyasic.misc import merge_dicts
|
|||||||
class MinerConfig:
|
class MinerConfig:
|
||||||
"""Represents the configuration for a miner including pool configuration,
|
"""Represents the configuration for a miner including pool configuration,
|
||||||
fan mode, temperature settings, mining mode, and power scaling."""
|
fan mode, temperature settings, mining mode, and power scaling."""
|
||||||
|
|
||||||
pools: PoolConfig = field(default_factory=PoolConfig.default)
|
pools: PoolConfig = field(default_factory=PoolConfig.default)
|
||||||
fan_mode: FanModeConfig = field(default_factory=FanModeConfig.default)
|
fan_mode: FanModeConfig = field(default_factory=FanModeConfig.default)
|
||||||
temperature: TemperatureConfig = field(default_factory=TemperatureConfig.default)
|
temperature: TemperatureConfig = field(default_factory=TemperatureConfig.default)
|
||||||
@@ -36,12 +35,6 @@ class MinerConfig:
|
|||||||
default_factory=PowerScalingConfig.default
|
default_factory=PowerScalingConfig.default
|
||||||
)
|
)
|
||||||
|
|
||||||
def __getitem__(self, item):
|
|
||||||
try:
|
|
||||||
return getattr(self, item)
|
|
||||||
except AttributeError:
|
|
||||||
raise KeyError
|
|
||||||
|
|
||||||
def as_dict(self) -> dict:
|
def as_dict(self) -> dict:
|
||||||
"""Converts the MinerConfig object to a dictionary."""
|
"""Converts the MinerConfig object to a dictionary."""
|
||||||
return asdict(self)
|
return asdict(self)
|
||||||
@@ -145,15 +138,6 @@ class MinerConfig:
|
|||||||
**self.power_scaling.as_auradine(),
|
**self.power_scaling.as_auradine(),
|
||||||
}
|
}
|
||||||
|
|
||||||
def as_mara(self, user_suffix: str = None) -> dict:
|
|
||||||
return {
|
|
||||||
**self.fan_mode.as_mara(),
|
|
||||||
**self.temperature.as_mara(),
|
|
||||||
**self.mining_mode.as_mara(),
|
|
||||||
**self.pools.as_mara(user_suffix=user_suffix),
|
|
||||||
**self.power_scaling.as_mara(),
|
|
||||||
}
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_dict(cls, dict_conf: dict) -> "MinerConfig":
|
def from_dict(cls, dict_conf: dict) -> "MinerConfig":
|
||||||
"""Constructs a MinerConfig object from a dictionary."""
|
"""Constructs a MinerConfig object from a dictionary."""
|
||||||
@@ -244,11 +228,3 @@ class MinerConfig:
|
|||||||
fan_mode=FanModeConfig.from_auradine(web_conf["fan"]),
|
fan_mode=FanModeConfig.from_auradine(web_conf["fan"]),
|
||||||
mining_mode=MiningModeConfig.from_auradine(web_conf["mode"]),
|
mining_mode=MiningModeConfig.from_auradine(web_conf["mode"]),
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_mara(cls, web_miner_config: dict) -> "MinerConfig":
|
|
||||||
return cls(
|
|
||||||
pools=PoolConfig.from_mara(web_miner_config),
|
|
||||||
fan_mode=FanModeConfig.from_mara(web_miner_config),
|
|
||||||
mining_mode=MiningModeConfig.from_mara(web_miner_config),
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -57,9 +57,6 @@ class MinerConfigOption(Enum):
|
|||||||
def as_auradine(self) -> dict:
|
def as_auradine(self) -> dict:
|
||||||
return self.value.as_auradine()
|
return self.value.as_auradine()
|
||||||
|
|
||||||
def as_mara(self) -> dict:
|
|
||||||
return self.value.as_mara()
|
|
||||||
|
|
||||||
def __call__(self, *args, **kwargs):
|
def __call__(self, *args, **kwargs):
|
||||||
return self.value(*args, **kwargs)
|
return self.value(*args, **kwargs)
|
||||||
|
|
||||||
@@ -67,13 +64,6 @@ class MinerConfigOption(Enum):
|
|||||||
def default(cls):
|
def default(cls):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def __getitem__(self, item):
|
|
||||||
try:
|
|
||||||
return getattr(self, item)
|
|
||||||
except AttributeError:
|
|
||||||
raise KeyError
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class MinerConfigValue:
|
class MinerConfigValue:
|
||||||
@@ -116,12 +106,3 @@ class MinerConfigValue:
|
|||||||
|
|
||||||
def as_auradine(self) -> dict:
|
def as_auradine(self) -> dict:
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
def as_mara(self) -> dict:
|
|
||||||
return {}
|
|
||||||
|
|
||||||
def __getitem__(self, item):
|
|
||||||
try:
|
|
||||||
return getattr(self, item)
|
|
||||||
except AttributeError:
|
|
||||||
raise KeyError
|
|
||||||
|
|||||||
@@ -71,15 +71,6 @@ class FanModeNormal(MinerConfigValue):
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def as_mara(self) -> dict:
|
|
||||||
return {
|
|
||||||
"general-config": {"environment-profile": "AirCooling"},
|
|
||||||
"advance-config": {
|
|
||||||
"override-fan-control": False,
|
|
||||||
"fan-fixed-percent": 0,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class FanModeManual(MinerConfigValue):
|
class FanModeManual(MinerConfigValue):
|
||||||
@@ -129,15 +120,6 @@ class FanModeManual(MinerConfigValue):
|
|||||||
def as_epic(self) -> dict:
|
def as_epic(self) -> dict:
|
||||||
return {"fans": {"Manual": {"speed": self.speed}}}
|
return {"fans": {"Manual": {"speed": self.speed}}}
|
||||||
|
|
||||||
def as_mara(self) -> dict:
|
|
||||||
return {
|
|
||||||
"general-config": {"environment-profile": "AirCooling"},
|
|
||||||
"advance-config": {
|
|
||||||
"override-fan-control": True,
|
|
||||||
"fan-fixed-percent": self.speed,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class FanModeImmersion(MinerConfigValue):
|
class FanModeImmersion(MinerConfigValue):
|
||||||
@@ -158,9 +140,6 @@ class FanModeImmersion(MinerConfigValue):
|
|||||||
def as_auradine(self) -> dict:
|
def as_auradine(self) -> dict:
|
||||||
return {"fan": {"percentage": 0}}
|
return {"fan": {"percentage": 0}}
|
||||||
|
|
||||||
def as_mara(self) -> dict:
|
|
||||||
return {"general-config": {"environment-profile": "OilImmersionCooling"}}
|
|
||||||
|
|
||||||
|
|
||||||
class FanModeConfig(MinerConfigOption):
|
class FanModeConfig(MinerConfigOption):
|
||||||
normal = FanModeNormal
|
normal = FanModeNormal
|
||||||
@@ -276,18 +255,4 @@ class FanModeConfig(MinerConfigOption):
|
|||||||
fan_1_target = fan_data["Target"]
|
fan_1_target = fan_data["Target"]
|
||||||
return cls.manual(speed=round((fan_1_target / fan_1_max) * 100))
|
return cls.manual(speed=round((fan_1_target / fan_1_max) * 100))
|
||||||
except LookupError:
|
except LookupError:
|
||||||
pass
|
|
||||||
return cls.default()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_mara(cls, web_config: dict):
|
|
||||||
try:
|
|
||||||
mode = web_config["general-config"]["environment-profile"]
|
|
||||||
if mode == "AirCooling":
|
|
||||||
if web_config["advance-config"]["override-fan-control"]:
|
|
||||||
return cls.manual(web_config["advance-config"]["fan-fixed-percent"])
|
|
||||||
return cls.normal()
|
|
||||||
return cls.immersion()
|
|
||||||
except LookupError:
|
|
||||||
pass
|
|
||||||
return cls.default()
|
return cls.default()
|
||||||
|
|||||||
@@ -56,13 +56,6 @@ class MiningModeNormal(MinerConfigValue):
|
|||||||
def as_goldshell(self) -> dict:
|
def as_goldshell(self) -> dict:
|
||||||
return {"settings": {"level": 0}}
|
return {"settings": {"level": 0}}
|
||||||
|
|
||||||
def as_mara(self) -> dict:
|
|
||||||
return {
|
|
||||||
"mode": {
|
|
||||||
"work-mode-selector": "Stock",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class MiningModeSleep(MinerConfigValue):
|
class MiningModeSleep(MinerConfigValue):
|
||||||
@@ -89,13 +82,6 @@ class MiningModeSleep(MinerConfigValue):
|
|||||||
def as_goldshell(self) -> dict:
|
def as_goldshell(self) -> dict:
|
||||||
return {"settings": {"level": 3}}
|
return {"settings": {"level": 3}}
|
||||||
|
|
||||||
def as_mara(self) -> dict:
|
|
||||||
return {
|
|
||||||
"mode": {
|
|
||||||
"work-mode-selector": "Sleep",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class MiningModeLPM(MinerConfigValue):
|
class MiningModeLPM(MinerConfigValue):
|
||||||
@@ -156,7 +142,6 @@ class VOptAlgo(MinerConfigValue):
|
|||||||
return "VoltageOptimizer"
|
return "VoltageOptimizer"
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class ChipTuneAlgo(MinerConfigValue):
|
class ChipTuneAlgo(MinerConfigValue):
|
||||||
mode: str = field(init=False, default="chip_tune")
|
mode: str = field(init=False, default="chip_tune")
|
||||||
|
|
||||||
@@ -234,24 +219,11 @@ class MiningModePowerTune(MinerConfigValue):
|
|||||||
def as_auradine(self) -> dict:
|
def as_auradine(self) -> dict:
|
||||||
return {"mode": {"mode": "custom", "tune": "power", "power": self.power}}
|
return {"mode": {"mode": "custom", "tune": "power", "power": self.power}}
|
||||||
|
|
||||||
def as_mara(self) -> dict:
|
|
||||||
return {
|
|
||||||
"mode": {
|
|
||||||
"work-mode-selector": "Auto",
|
|
||||||
"concorde": {
|
|
||||||
"mode-select": "PowerTarget",
|
|
||||||
"power-target": self.power,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class MiningModeHashrateTune(MinerConfigValue):
|
class MiningModeHashrateTune(MinerConfigValue):
|
||||||
mode: str = field(init=False, default="hashrate_tuning")
|
mode: str = field(init=False, default="hashrate_tuning")
|
||||||
hashrate: int = None
|
hashrate: int = None
|
||||||
throttle_limit: int = None
|
|
||||||
throttle_step: int = None
|
|
||||||
algo: TunerAlgo = field(default_factory=TunerAlgo.default)
|
algo: TunerAlgo = field(default_factory=TunerAlgo.default)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -259,10 +231,6 @@ class MiningModeHashrateTune(MinerConfigValue):
|
|||||||
cls_conf = {}
|
cls_conf = {}
|
||||||
if dict_conf.get("hashrate"):
|
if dict_conf.get("hashrate"):
|
||||||
cls_conf["hashrate"] = dict_conf["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"):
|
if dict_conf.get("algo"):
|
||||||
cls_conf["algo"] = TunerAlgo.from_dict(dict_conf["algo"])
|
cls_conf["algo"] = TunerAlgo.from_dict(dict_conf["algo"])
|
||||||
|
|
||||||
@@ -299,28 +267,7 @@ class MiningModeHashrateTune(MinerConfigValue):
|
|||||||
return {"mode": {"mode": "custom", "tune": "ths", "ths": self.hashrate}}
|
return {"mode": {"mode": "custom", "tune": "ths", "ths": self.hashrate}}
|
||||||
|
|
||||||
def as_epic(self) -> dict:
|
def as_epic(self) -> dict:
|
||||||
mode = {
|
return {"ptune": {"algo": self.algo.as_epic(), "target": self.hashrate}}
|
||||||
"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 {
|
|
||||||
"mode": {
|
|
||||||
"work-mode-selector": "Auto",
|
|
||||||
"concorde": {
|
|
||||||
"mode-select": "Hashrate",
|
|
||||||
"hash-target": self.hashrate,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@@ -373,17 +320,6 @@ class MiningModeManual(MinerConfigValue):
|
|||||||
}
|
}
|
||||||
return cls(global_freq=freq, global_volt=voltage, boards=boards)
|
return cls(global_freq=freq, global_volt=voltage, boards=boards)
|
||||||
|
|
||||||
def as_mara(self) -> dict:
|
|
||||||
return {
|
|
||||||
"mode": {
|
|
||||||
"work-mode-selector": "Fixed",
|
|
||||||
"fixed": {
|
|
||||||
"frequency": str(self.global_freq),
|
|
||||||
"voltage": self.global_volt,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class MiningModeConfig(MinerConfigOption):
|
class MiningModeConfig(MinerConfigOption):
|
||||||
normal = MiningModeNormal
|
normal = MiningModeNormal
|
||||||
@@ -433,19 +369,13 @@ class MiningModeConfig(MinerConfigOption):
|
|||||||
algo_info = web_conf["PerpetualTune"]["Algorithm"]
|
algo_info = web_conf["PerpetualTune"]["Algorithm"]
|
||||||
if algo_info.get("VoltageOptimizer") is not None:
|
if algo_info.get("VoltageOptimizer") is not None:
|
||||||
return cls.hashrate_tuning(
|
return cls.hashrate_tuning(
|
||||||
hashrate=algo_info["VoltageOptimizer"].get("Target"),
|
hashrate=algo_info["VoltageOptimizer"]["Target"],
|
||||||
throttle_limit=algo_info["VoltageOptimizer"].get(
|
algo=TunerAlgo.voltage_optimizer,
|
||||||
"Min Throttle Target"
|
|
||||||
),
|
|
||||||
throttle_step=algo_info["VoltageOptimizer"].get(
|
|
||||||
"Throttle Step"
|
|
||||||
),
|
|
||||||
algo=TunerAlgo.voltage_optimizer(),
|
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
return cls.hashrate_tuning(
|
return cls.hashrate_tuning(
|
||||||
hashrate=algo_info["ChipTune"].get("Target"),
|
hashrate=algo_info["ChipTune"]["Target"],
|
||||||
algo=TunerAlgo.chip_tune(),
|
algo=TunerAlgo.chip_tune,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
return cls.normal()
|
return cls.normal()
|
||||||
@@ -538,28 +468,3 @@ class MiningModeConfig(MinerConfigOption):
|
|||||||
return cls.power_tuning(mode_data["Power"])
|
return cls.power_tuning(mode_data["Power"])
|
||||||
except LookupError:
|
except LookupError:
|
||||||
return cls.default()
|
return cls.default()
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_mara(cls, web_config: dict):
|
|
||||||
try:
|
|
||||||
mode = web_config["mode"]["work-mode-selector"]
|
|
||||||
if mode == "Fixed":
|
|
||||||
fixed_conf = web_config["mode"]["fixed"]
|
|
||||||
return cls.manual(
|
|
||||||
global_freq=int(fixed_conf["frequency"]),
|
|
||||||
global_volt=fixed_conf["voltage"],
|
|
||||||
)
|
|
||||||
elif mode == "Stock":
|
|
||||||
return cls.normal()
|
|
||||||
elif mode == "Sleep":
|
|
||||||
return cls.sleep()
|
|
||||||
elif mode == "Auto":
|
|
||||||
auto_conf = web_config["mode"]["concorde"]
|
|
||||||
auto_mode = auto_conf["mode-select"]
|
|
||||||
if auto_mode == "Hashrate":
|
|
||||||
return cls.hashrate_tuning(hashrate=auto_conf["hash-target"])
|
|
||||||
elif auto_mode == "PowerTarget":
|
|
||||||
return cls.power_tuning(power=auto_conf["power-target"])
|
|
||||||
except LookupError:
|
|
||||||
pass
|
|
||||||
return cls.default()
|
|
||||||
|
|||||||
@@ -118,15 +118,6 @@ class Pool(MinerConfigValue):
|
|||||||
}
|
}
|
||||||
return {"pool": self.url, "login": self.user, "password": self.password}
|
return {"pool": self.url, "login": self.user, "password": self.password}
|
||||||
|
|
||||||
def as_mara(self, user_suffix: str = None) -> dict:
|
|
||||||
if user_suffix is not None:
|
|
||||||
return {
|
|
||||||
"url": self.url,
|
|
||||||
"user": f"{self.user}{user_suffix}",
|
|
||||||
"pass": self.password,
|
|
||||||
}
|
|
||||||
return {"url": self.url, "user": self.user, "pass": self.password}
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_dict(cls, dict_conf: dict | None) -> "Pool":
|
def from_dict(cls, dict_conf: dict | None) -> "Pool":
|
||||||
return cls(
|
return cls(
|
||||||
@@ -186,14 +177,6 @@ class Pool(MinerConfigValue):
|
|||||||
password=grpc_pool["password"],
|
password=grpc_pool["password"],
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_mara(cls, web_pool: dict) -> "Pool":
|
|
||||||
return cls(
|
|
||||||
url=web_pool["url"],
|
|
||||||
user=web_pool["user"],
|
|
||||||
password=web_pool["pass"],
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class PoolGroup(MinerConfigValue):
|
class PoolGroup(MinerConfigValue):
|
||||||
@@ -281,12 +264,9 @@ class PoolGroup(MinerConfigValue):
|
|||||||
def as_auradine(self, user_suffix: str = None) -> list:
|
def as_auradine(self, user_suffix: str = None) -> list:
|
||||||
return [p.as_auradine(user_suffix=user_suffix) for p in self.pools]
|
return [p.as_auradine(user_suffix=user_suffix) for p in self.pools]
|
||||||
|
|
||||||
def as_epic(self, user_suffix: str = None) -> list:
|
def as_epic(self, user_suffix: str = None) -> dict:
|
||||||
return [p.as_epic(user_suffix=user_suffix) for p in self.pools]
|
return [p.as_epic(user_suffix=user_suffix) for p in self.pools]
|
||||||
|
|
||||||
def as_mara(self, user_suffix: str = None) -> list:
|
|
||||||
return [p.as_mara(user_suffix=user_suffix) for p in self.pools]
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_dict(cls, dict_conf: dict | None) -> "PoolGroup":
|
def from_dict(cls, dict_conf: dict | None) -> "PoolGroup":
|
||||||
cls_conf = {}
|
cls_conf = {}
|
||||||
@@ -356,10 +336,6 @@ class PoolGroup(MinerConfigValue):
|
|||||||
except LookupError:
|
except LookupError:
|
||||||
return cls()
|
return cls()
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_mara(cls, web_config_pools: dict) -> "PoolGroup":
|
|
||||||
return cls(pools=[Pool.from_mara(pool_conf) for pool_conf in web_config_pools])
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class PoolConfig(MinerConfigValue):
|
class PoolConfig(MinerConfigValue):
|
||||||
@@ -451,11 +427,6 @@ class PoolConfig(MinerConfigValue):
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def as_mara(self, user_suffix: str = None) -> dict:
|
|
||||||
if len(self.groups) > 0:
|
|
||||||
return {"pools": self.groups[0].as_mara(user_suffix=user_suffix)}
|
|
||||||
return {"pools": []}
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_api(cls, api_pools: dict) -> "PoolConfig":
|
def from_api(cls, api_pools: dict) -> "PoolConfig":
|
||||||
try:
|
try:
|
||||||
@@ -510,7 +481,3 @@ class PoolConfig(MinerConfigValue):
|
|||||||
)
|
)
|
||||||
except LookupError:
|
except LookupError:
|
||||||
return cls()
|
return cls()
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_mara(cls, web_config: dict) -> "PoolConfig":
|
|
||||||
return cls(groups=[PoolGroup.from_mara(web_config["pools"])])
|
|
||||||
|
|||||||
@@ -38,8 +38,6 @@ class TemperatureConfig(MinerConfigValue):
|
|||||||
temp_cfg["hot_temp"] = self.hot
|
temp_cfg["hot_temp"] = self.hot
|
||||||
if self.danger is not None:
|
if self.danger is not None:
|
||||||
temp_cfg["dangerous_temp"] = self.danger
|
temp_cfg["dangerous_temp"] = self.danger
|
||||||
if len(temp_cfg) == 0:
|
|
||||||
return {}
|
|
||||||
return {"temp_control": temp_cfg}
|
return {"temp_control": temp_cfg}
|
||||||
|
|
||||||
def as_epic(self) -> dict:
|
def as_epic(self) -> dict:
|
||||||
@@ -49,9 +47,7 @@ class TemperatureConfig(MinerConfigValue):
|
|||||||
else:
|
else:
|
||||||
temps_config["fans"]["Auto"]["Target Temperature"] = 60
|
temps_config["fans"]["Auto"]["Target Temperature"] = 60
|
||||||
if self.danger is not None:
|
if self.danger is not None:
|
||||||
temps_config["temps"]["critical"] = self.danger
|
temps_config["temps"]["shutdown"] = self.danger
|
||||||
if self.hot is not None:
|
|
||||||
temps_config["temps"]["shutdown"] = self.hot
|
|
||||||
return temps_config
|
return temps_config
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -71,25 +67,20 @@ class TemperatureConfig(MinerConfigValue):
|
|||||||
hot=temp_control.get("hot_temp"),
|
hot=temp_control.get("hot_temp"),
|
||||||
danger=temp_control.get("dangerous_temp"),
|
danger=temp_control.get("dangerous_temp"),
|
||||||
)
|
)
|
||||||
return cls()
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_epic(cls, web_conf: dict) -> "TemperatureConfig":
|
def from_epic(cls, web_conf: dict) -> "TemperatureConfig":
|
||||||
try:
|
try:
|
||||||
dangerous_temp = web_conf["Misc"]["Critical Temp"]
|
dangerous_temp = web_conf["Misc"]["Shutdown Temp"]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
dangerous_temp = None
|
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
|
# Need to do this in two blocks to avoid KeyError if one is missing
|
||||||
try:
|
try:
|
||||||
target_temp = web_conf["Fans"]["Fan Mode"]["Auto"]["Target Temperature"]
|
target_temp = web_conf["Fans"]["Fan Mode"]["Auto"]["Target Temperature"]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
target_temp = None
|
target_temp = None
|
||||||
|
|
||||||
return cls(target=target_temp, hot=hot_temp, danger=dangerous_temp)
|
return cls(target=target_temp, danger=dangerous_temp)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_vnish(cls, web_settings: dict) -> "TemperatureConfig":
|
def from_vnish(cls, web_settings: dict) -> "TemperatureConfig":
|
||||||
|
|||||||
@@ -25,10 +25,8 @@ from pyasic.config import MinerConfig
|
|||||||
from pyasic.config.mining import MiningModePowerTune
|
from pyasic.config.mining import MiningModePowerTune
|
||||||
|
|
||||||
from .boards import HashBoard
|
from .boards import HashBoard
|
||||||
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,11 +38,8 @@ class MinerData:
|
|||||||
datetime: The time and date this data was generated.
|
datetime: The time and date this data was generated.
|
||||||
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.
|
|
||||||
model: The model of the miner as a str.
|
model: The model of the miner as a str.
|
||||||
make: The make 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.
|
||||||
@@ -55,10 +50,8 @@ class MinerData:
|
|||||||
temperature_avg: The average temperature across the boards. Calculated automatically.
|
temperature_avg: The average temperature across the boards. Calculated automatically.
|
||||||
env_temp: The environment temps as a float.
|
env_temp: The environment temps as a float.
|
||||||
wattage: Current power draw of the miner as an int.
|
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.
|
wattage_limit: Power limit of the miner as an int.
|
||||||
fans: A list of fans on the miner with their speeds.
|
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.
|
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.
|
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.
|
expected_chips: The expected number of chips in the miner as an int.
|
||||||
@@ -73,62 +66,34 @@ class MinerData:
|
|||||||
is_mining: Whether the miner is mining.
|
is_mining: Whether the miner is mining.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# general
|
|
||||||
ip: str
|
ip: str
|
||||||
_datetime: datetime = field(repr=False, default=None)
|
datetime: datetime = None
|
||||||
datetime: str = field(init=False)
|
uptime: int = None
|
||||||
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
|
mac: str = None
|
||||||
|
model: str = None
|
||||||
|
make: 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: float = field(init=False)
|
||||||
# hashrate
|
_hashrate: float = field(repr=False, default=None)
|
||||||
hashrate: AlgoHashRate = field(init=False)
|
|
||||||
_hashrate: AlgoHashRate = field(repr=False, default=None)
|
|
||||||
|
|
||||||
# expected
|
|
||||||
expected_hashrate: float = None
|
expected_hashrate: float = None
|
||||||
|
hashboards: List[HashBoard] = field(default_factory=list)
|
||||||
expected_hashboards: int = None
|
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_chips: int = None
|
||||||
expected_fans: int = None
|
|
||||||
|
|
||||||
# % expected
|
|
||||||
percent_expected_chips: float = field(init=False)
|
percent_expected_chips: float = field(init=False)
|
||||||
percent_expected_hashrate: float = field(init=False)
|
percent_expected_hashrate: float = field(init=False)
|
||||||
percent_expected_wattage: 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)
|
nominal: bool = field(init=False)
|
||||||
|
|
||||||
# config
|
|
||||||
config: MinerConfig = None
|
config: MinerConfig = None
|
||||||
fault_light: Union[bool, None] = None
|
|
||||||
|
|
||||||
# errors
|
|
||||||
errors: List[
|
errors: List[
|
||||||
Union[
|
Union[
|
||||||
WhatsminerError,
|
WhatsminerError,
|
||||||
@@ -137,11 +102,9 @@ class MinerData:
|
|||||||
InnosiliconError,
|
InnosiliconError,
|
||||||
]
|
]
|
||||||
] = field(default_factory=list)
|
] = field(default_factory=list)
|
||||||
|
fault_light: Union[bool, None] = None
|
||||||
# mining state
|
|
||||||
is_mining: bool = True
|
|
||||||
uptime: int = None
|
|
||||||
efficiency: int = field(init=False)
|
efficiency: int = field(init=False)
|
||||||
|
is_mining: bool = True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def fields(cls):
|
def fields(cls):
|
||||||
@@ -152,7 +115,7 @@ class MinerData:
|
|||||||
return {k: v for (k, v) in x if not k.startswith("_")}
|
return {k: v for (k, v) in x if not k.startswith("_")}
|
||||||
|
|
||||||
def __post_init__(self):
|
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):
|
def get(self, __key: str, default: Any = None):
|
||||||
try:
|
try:
|
||||||
@@ -220,7 +183,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 sum(hr_data, start=type(hr_data[0])(0))
|
return round(sum(hr_data), 2)
|
||||||
return self._hashrate
|
return self._hashrate
|
||||||
|
|
||||||
@hashrate.setter
|
@hashrate.setter
|
||||||
@@ -279,10 +242,9 @@ class MinerData:
|
|||||||
def percent_expected_hashrate(self): # noqa - Skip PyCharm inspection
|
def percent_expected_hashrate(self): # noqa - Skip PyCharm inspection
|
||||||
if self.hashrate is None or self.expected_hashrate is None:
|
if self.hashrate is None or self.expected_hashrate is None:
|
||||||
return None
|
return None
|
||||||
try:
|
if self.hashrate == 0 or self.expected_hashrate == 0:
|
||||||
return round((self.hashrate / self.expected_hashrate) * 100)
|
|
||||||
except ZeroDivisionError:
|
|
||||||
return 0
|
return 0
|
||||||
|
return round((self.hashrate / self.expected_hashrate) * 100)
|
||||||
|
|
||||||
@percent_expected_hashrate.setter
|
@percent_expected_hashrate.setter
|
||||||
def percent_expected_hashrate(self, val):
|
def percent_expected_hashrate(self, val):
|
||||||
@@ -292,10 +254,9 @@ class MinerData:
|
|||||||
def percent_expected_wattage(self): # noqa - Skip PyCharm inspection
|
def percent_expected_wattage(self): # noqa - Skip PyCharm inspection
|
||||||
if self.wattage_limit is None or self.wattage is None:
|
if self.wattage_limit is None or self.wattage is None:
|
||||||
return None
|
return None
|
||||||
try:
|
if self.wattage_limit == 0 or self.wattage == 0:
|
||||||
return round((self.wattage / self.wattage_limit) * 100)
|
|
||||||
except ZeroDivisionError:
|
|
||||||
return 0
|
return 0
|
||||||
|
return round((self.wattage / self.wattage_limit) * 100)
|
||||||
|
|
||||||
@percent_expected_wattage.setter
|
@percent_expected_wattage.setter
|
||||||
def percent_expected_wattage(self, val):
|
def percent_expected_wattage(self, val):
|
||||||
@@ -321,70 +282,14 @@ class MinerData:
|
|||||||
def efficiency(self): # noqa - Skip PyCharm inspection
|
def efficiency(self): # noqa - Skip PyCharm inspection
|
||||||
if self.hashrate is None or self.wattage is None:
|
if self.hashrate is None or self.wattage is None:
|
||||||
return None
|
return None
|
||||||
try:
|
if self.hashrate == 0 or self.wattage == 0:
|
||||||
return round(self.wattage / float(self.hashrate))
|
|
||||||
except ZeroDivisionError:
|
|
||||||
return 0
|
return 0
|
||||||
|
return round(self.wattage / self.hashrate)
|
||||||
|
|
||||||
@efficiency.setter
|
@efficiency.setter
|
||||||
def efficiency(self, val):
|
def efficiency(self, val):
|
||||||
pass
|
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:
|
def asdict(self) -> dict:
|
||||||
return asdict(self, dict_factory=self.dict_factory)
|
return asdict(self, dict_factory=self.dict_factory)
|
||||||
|
|
||||||
@@ -402,7 +307,9 @@ class MinerData:
|
|||||||
Returns:
|
Returns:
|
||||||
A JSON version of this class.
|
A JSON version of this class.
|
||||||
"""
|
"""
|
||||||
return json.dumps(self.as_dict())
|
data = self.asdict()
|
||||||
|
data["datetime"] = str(int(time.mktime(data["datetime"].timetuple())))
|
||||||
|
return json.dumps(data)
|
||||||
|
|
||||||
def as_csv(self) -> str:
|
def as_csv(self) -> str:
|
||||||
"""Get this dataclass as CSV.
|
"""Get this dataclass as CSV.
|
||||||
@@ -411,6 +318,7 @@ class MinerData:
|
|||||||
A CSV version of this class with no headers.
|
A CSV version of this class with no headers.
|
||||||
"""
|
"""
|
||||||
data = self.asdict()
|
data = self.asdict()
|
||||||
|
data["datetime"] = str(int(time.mktime(data["datetime"].timetuple())))
|
||||||
errs = []
|
errs = []
|
||||||
for error in data["errors"]:
|
for error in data["errors"]:
|
||||||
errs.append(error["error_message"])
|
errs.append(error["error_message"])
|
||||||
@@ -475,6 +383,6 @@ class MinerData:
|
|||||||
|
|
||||||
tags_str = ",".join(tag_data)
|
tags_str = ",".join(tag_data)
|
||||||
field_str = ",".join(field_data)
|
field_str = ",".join(field_data)
|
||||||
timestamp = str(self.timestamp * 1e9)
|
timestamp = str(int(time.mktime(self.datetime.timetuple()) * 1e9))
|
||||||
|
|
||||||
return " ".join([tags_str, field_str, timestamp])
|
return " ".join([tags_str, field_str, timestamp])
|
||||||
|
|||||||
@@ -17,8 +17,6 @@
|
|||||||
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:
|
||||||
@@ -36,7 +34,7 @@ class HashBoard:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
slot: int = 0
|
slot: int = 0
|
||||||
hashrate: AlgoHashRate = None
|
hashrate: float = None
|
||||||
temp: int = None
|
temp: int = None
|
||||||
chip_temp: int = None
|
chip_temp: int = None
|
||||||
chips: int = None
|
chips: int = None
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
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
|
|
||||||
)
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
from .algorithm import MinerAlgo
|
|
||||||
from .firmware import MinerFirmware
|
|
||||||
from .makes import MinerMake
|
|
||||||
from .models import MinerModel
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
from pyasic.device.algorithm.sha256 import SHA256Algo
|
|
||||||
|
|
||||||
|
|
||||||
class MinerAlgo:
|
|
||||||
SHA256 = SHA256Algo
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
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")
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
# ------------------------------------------------------------------------------
|
|
||||||
# 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 StrEnum
|
|
||||||
|
|
||||||
|
|
||||||
class MinerFirmware(StrEnum):
|
|
||||||
STOCK = "Stock"
|
|
||||||
BRAIINS_OS = "BOS+"
|
|
||||||
VNISH = "VNish"
|
|
||||||
EPIC = "ePIC"
|
|
||||||
HIVEON = "Hive"
|
|
||||||
LUXOS = "LuxOS"
|
|
||||||
MARATHON = "MaraFW"
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
# ------------------------------------------------------------------------------
|
|
||||||
# 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 StrEnum
|
|
||||||
|
|
||||||
|
|
||||||
class MinerMake(StrEnum):
|
|
||||||
WHATSMINER = "WhatsMiner"
|
|
||||||
ANTMINER = "AntMiner"
|
|
||||||
AVALONMINER = "AvalonMiner"
|
|
||||||
INNOSILICON = "Innosilicon"
|
|
||||||
GOLDSHELL = "Goldshell"
|
|
||||||
AURADINE = "Auradine"
|
|
||||||
EPIC = "ePIC"
|
|
||||||
@@ -1,318 +0,0 @@
|
|||||||
from enum import StrEnum
|
|
||||||
|
|
||||||
|
|
||||||
class AntminerModels(StrEnum):
|
|
||||||
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"
|
|
||||||
|
|
||||||
|
|
||||||
class WhatsminerModels(StrEnum):
|
|
||||||
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"
|
|
||||||
|
|
||||||
|
|
||||||
class AvalonminerModels(StrEnum):
|
|
||||||
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"
|
|
||||||
|
|
||||||
|
|
||||||
class InnosiliconModels(StrEnum):
|
|
||||||
T3HPlus = "T3H+"
|
|
||||||
A10X = "A10X"
|
|
||||||
|
|
||||||
|
|
||||||
class GoldshellModels(StrEnum):
|
|
||||||
CK5 = "CK5"
|
|
||||||
HS5 = "HS5"
|
|
||||||
KD5 = "KD5"
|
|
||||||
KDMax = "KD Max"
|
|
||||||
KDBoxII = "KD Box II"
|
|
||||||
KDBoxPro = "KD Box Pro"
|
|
||||||
|
|
||||||
|
|
||||||
class ePICModels(StrEnum):
|
|
||||||
BM520i = "BlockMiner 520i"
|
|
||||||
BM720i = "BlockMiner 720i"
|
|
||||||
|
|
||||||
|
|
||||||
class AuradineModels(StrEnum):
|
|
||||||
AT1500 = "AT1500"
|
|
||||||
AT2860 = "AT2860"
|
|
||||||
AT2880 = "AT2880"
|
|
||||||
AI2500 = "AI2500"
|
|
||||||
AI3680 = "AI3680"
|
|
||||||
AD2500 = "AD2500"
|
|
||||||
AD3500 = "AD3500"
|
|
||||||
|
|
||||||
|
|
||||||
class MinerModel:
|
|
||||||
ANTMINER = AntminerModels
|
|
||||||
WHATSMINER = WhatsminerModels
|
|
||||||
AVALONMINER = AvalonminerModels
|
|
||||||
INNOSILICON = InnosiliconModels
|
|
||||||
GOLDSHELL = GoldshellModels
|
|
||||||
AURADINE = AuradineModels
|
|
||||||
EPIC = ePICModels
|
|
||||||
@@ -20,16 +20,7 @@ from typing import List, Union
|
|||||||
from pyasic.errors import APIError
|
from pyasic.errors import APIError
|
||||||
from pyasic.miners import AnyMiner
|
from pyasic.miners import AnyMiner
|
||||||
from pyasic.miners.backends import AntminerModern, BOSMiner, BTMiner
|
from pyasic.miners.backends import AntminerModern, BOSMiner, BTMiner
|
||||||
from pyasic.miners.device.models import (
|
from pyasic.miners.models import S9, S17, T17, S17e, S17Plus, S17Pro, T17e, T17Plus
|
||||||
S9,
|
|
||||||
S17,
|
|
||||||
T17,
|
|
||||||
S17e,
|
|
||||||
S17Plus,
|
|
||||||
S17Pro,
|
|
||||||
T17e,
|
|
||||||
T17Plus,
|
|
||||||
)
|
|
||||||
|
|
||||||
FAN_USAGE = 50 # 50 W per fan
|
FAN_USAGE = 50 # 50 W per fan
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import AntminerOld
|
from pyasic.miners.backends import AntminerOld
|
||||||
from pyasic.miners.device.models import S17, S17e, S17Plus, S17Pro
|
from pyasic.miners.models import S17, S17e, S17Plus, S17Pro
|
||||||
|
|
||||||
|
|
||||||
class BMMinerS17(AntminerOld, S17):
|
class BMMinerS17(AntminerOld, S17):
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import AntminerOld
|
from pyasic.miners.backends import AntminerOld
|
||||||
from pyasic.miners.device.models import T17, T17e, T17Plus
|
from pyasic.miners.models import T17, T17e, T17Plus
|
||||||
|
|
||||||
|
|
||||||
class BMMinerT17(AntminerOld, T17):
|
class BMMinerT17(AntminerOld, T17):
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import AntminerModern
|
from pyasic.miners.backends import AntminerModern
|
||||||
from pyasic.miners.device.models import (
|
from pyasic.miners.models import (
|
||||||
S19,
|
S19,
|
||||||
S19L,
|
S19L,
|
||||||
S19XP,
|
S19XP,
|
||||||
@@ -26,12 +26,12 @@ from pyasic.miners.device.models import (
|
|||||||
S19j,
|
S19j,
|
||||||
S19jNoPIC,
|
S19jNoPIC,
|
||||||
S19jPro,
|
S19jPro,
|
||||||
S19KPro,
|
|
||||||
S19Plus,
|
S19Plus,
|
||||||
S19Pro,
|
S19Pro,
|
||||||
S19ProHydro,
|
S19ProHydro,
|
||||||
S19ProPlus,
|
S19ProPlus,
|
||||||
S19ProPlusHydro,
|
S19ProPlusHydro,
|
||||||
|
S19KPro,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import AntminerModern
|
from pyasic.miners.backends import AntminerModern
|
||||||
from pyasic.miners.device.models import T19
|
from pyasic.miners.models import T19
|
||||||
|
|
||||||
|
|
||||||
class BMMinerT19(AntminerModern, T19):
|
class BMMinerT19(AntminerModern, T19):
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import AntminerModern
|
from pyasic.miners.backends import AntminerModern
|
||||||
from pyasic.miners.device.models import S21
|
from pyasic.miners.models import S21
|
||||||
|
|
||||||
|
|
||||||
class BMMinerS21(AntminerModern, S21):
|
class BMMinerS21(AntminerModern, S21):
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import AntminerModern
|
from pyasic.miners.backends import AntminerModern
|
||||||
from pyasic.miners.device.models import T21
|
from pyasic.miners.models import T21
|
||||||
|
|
||||||
|
|
||||||
class BMMinerT21(AntminerModern, T21):
|
class BMMinerT21(AntminerModern, T21):
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import AntminerModern
|
from pyasic.miners.backends import AntminerModern
|
||||||
from pyasic.miners.device.models import HS3
|
from pyasic.miners.models import HS3
|
||||||
|
|
||||||
|
|
||||||
class BMMinerHS3(AntminerModern, HS3):
|
class BMMinerHS3(AntminerModern, HS3):
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import AntminerOld
|
from pyasic.miners.backends import AntminerOld
|
||||||
from pyasic.miners.device.models import L3Plus
|
from pyasic.miners.models import L3Plus
|
||||||
|
|
||||||
|
|
||||||
class BMMinerL3Plus(AntminerOld, L3Plus):
|
class BMMinerL3Plus(AntminerOld, L3Plus):
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
# limitations under the License. -
|
# limitations under the License. -
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
from pyasic.miners.backends import AntminerModern
|
from pyasic.miners.backends import AntminerModern
|
||||||
from pyasic.miners.device.models import L7
|
from pyasic.miners.models import L7
|
||||||
|
|
||||||
|
|
||||||
class BMMinerL7(AntminerModern, L7):
|
class BMMinerL7(AntminerModern, L7):
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import AntminerModern
|
from pyasic.miners.backends import AntminerModern
|
||||||
from pyasic.miners.device.models import E9Pro
|
from pyasic.miners.models import E9Pro
|
||||||
|
|
||||||
|
|
||||||
class BMMinerE9Pro(AntminerModern, E9Pro):
|
class BMMinerE9Pro(AntminerModern, E9Pro):
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import BMMiner
|
from pyasic.miners.backends import BMMiner
|
||||||
from pyasic.miners.device.models import S9, S9i, S9j
|
from pyasic.miners.models import S9, S9i, S9j
|
||||||
|
|
||||||
|
|
||||||
class BMMinerS9(BMMiner, S9):
|
class BMMinerS9(BMMiner, S9):
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import BMMiner
|
from pyasic.miners.backends import BMMiner
|
||||||
from pyasic.miners.device.models import T9
|
from pyasic.miners.models import T9
|
||||||
|
|
||||||
|
|
||||||
class BMMinerT9(BMMiner, T9):
|
class BMMinerT9(BMMiner, T9):
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import BOSMiner
|
from pyasic.miners.backends import BOSMiner
|
||||||
from pyasic.miners.device.models import S17, S17e, S17Plus, S17Pro
|
from pyasic.miners.models import S17, S17e, S17Plus, S17Pro
|
||||||
|
|
||||||
|
|
||||||
class BOSMinerS17(BOSMiner, S17):
|
class BOSMinerS17(BOSMiner, S17):
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import BOSMiner
|
from pyasic.miners.backends import BOSMiner
|
||||||
from pyasic.miners.device.models import T17, T17e, T17Plus
|
from pyasic.miners.models import T17, T17e, T17Plus
|
||||||
|
|
||||||
|
|
||||||
class BOSMinerT17(BOSMiner, T17):
|
class BOSMinerT17(BOSMiner, T17):
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import BOSer
|
from pyasic.miners.backends import BOSer
|
||||||
from pyasic.miners.device.models import (
|
from pyasic.miners.models import (
|
||||||
S19,
|
S19,
|
||||||
S19XP,
|
S19XP,
|
||||||
S19a,
|
S19a,
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import BOSer
|
from pyasic.miners.backends import BOSer
|
||||||
from pyasic.miners.device.models import T19
|
from pyasic.miners.models import T19
|
||||||
|
|
||||||
|
|
||||||
class BOSMinerT19(BOSer, T19):
|
class BOSMinerT19(BOSer, T19):
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import BOSer
|
from pyasic.miners.backends import BOSer
|
||||||
from pyasic.miners.device.models import S21
|
from pyasic.miners.models import S21
|
||||||
|
|
||||||
|
|
||||||
class BOSMinerS21(BOSer, S21):
|
class BOSMinerS21(BOSer, S21):
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import BOSMiner
|
from pyasic.miners.backends import BOSMiner
|
||||||
from pyasic.miners.device.models import S9
|
from pyasic.miners.models import S9
|
||||||
|
|
||||||
|
|
||||||
class BOSMinerS9(BOSMiner, S9):
|
class BOSMinerS9(BOSMiner, S9):
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import AntminerOld
|
from pyasic.miners.backends import AntminerOld
|
||||||
from pyasic.miners.device.models import Z15
|
from pyasic.miners.models import Z15
|
||||||
|
|
||||||
|
|
||||||
class CGMinerZ15(AntminerOld, Z15):
|
class CGMinerZ15(AntminerOld, Z15):
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
# limitations under the License. -
|
# limitations under the License. -
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
from pyasic.miners.backends import AntminerOld
|
from pyasic.miners.backends import AntminerOld
|
||||||
from pyasic.miners.device.models import D3
|
from pyasic.miners.models import D3
|
||||||
|
|
||||||
|
|
||||||
class CGMinerD3(AntminerOld, D3):
|
class CGMinerD3(AntminerOld, D3):
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import AntminerOld
|
from pyasic.miners.backends import AntminerOld
|
||||||
from pyasic.miners.device.models import DR5
|
from pyasic.miners.models import DR5
|
||||||
|
|
||||||
|
|
||||||
class CGMinerDR5(AntminerOld, DR5):
|
class CGMinerDR5(AntminerOld, DR5):
|
||||||
|
|||||||
@@ -15,15 +15,7 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import ePIC
|
from pyasic.miners.backends import ePIC
|
||||||
from pyasic.miners.device.models import (
|
from pyasic.miners.models import S19, S19XP, S19j, S19jPro, S19jProPlus, S19kPro, S19Pro
|
||||||
S19,
|
|
||||||
S19XP,
|
|
||||||
S19j,
|
|
||||||
S19jPro,
|
|
||||||
S19jProPlus,
|
|
||||||
S19kPro,
|
|
||||||
S19Pro,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class ePICS19(ePIC, S19):
|
class ePICS19(ePIC, S19):
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import ePIC
|
from pyasic.miners.backends import ePIC
|
||||||
from pyasic.miners.device.models import S21
|
from pyasic.miners.models import S21
|
||||||
|
|
||||||
|
|
||||||
class ePICS21(ePIC, S21):
|
class ePICS21(ePIC, S21):
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import ePIC
|
from pyasic.miners.backends import ePIC
|
||||||
from pyasic.miners.device.models import T21
|
from pyasic.miners.models import T21
|
||||||
|
|
||||||
|
|
||||||
class ePICT21(ePIC, T21):
|
class ePICT21(ePIC, T21):
|
||||||
|
|||||||
@@ -18,11 +18,11 @@ from typing import List, Optional
|
|||||||
|
|
||||||
import asyncssh
|
import asyncssh
|
||||||
|
|
||||||
from pyasic.data import AlgoHashRate, HashBoard, HashUnit
|
from pyasic.data import HashBoard
|
||||||
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
|
||||||
from pyasic.miners.device.models import T9
|
from pyasic.miners.models import T9
|
||||||
|
|
||||||
HIVEON_T9_DATA_LOC = DataLocations(
|
HIVEON_T9_DATA_LOC = DataLocations(
|
||||||
**{
|
**{
|
||||||
@@ -121,9 +121,7 @@ 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 = AlgoHashRate.SHA256(
|
hashboards[board].hashrate = round(hashrate / 1000, 2)
|
||||||
hashrate, HashUnit.SHA256.GH
|
|
||||||
).into(self.algo.unit.default)
|
|
||||||
hashboards[board].chips = chips
|
hashboards[board].chips = chips
|
||||||
|
|
||||||
return hashboards
|
return hashboards
|
||||||
|
|||||||
@@ -15,14 +15,7 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import LUXMiner
|
from pyasic.miners.backends import LUXMiner
|
||||||
from pyasic.miners.device.models import (
|
from pyasic.miners.models import S19, S19XP, S19jPro, S19jProPlus, S19kPro, S19Pro
|
||||||
S19,
|
|
||||||
S19XP,
|
|
||||||
S19jPro,
|
|
||||||
S19jProPlus,
|
|
||||||
S19kPro,
|
|
||||||
S19Pro,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class LUXMinerS19(LUXMiner, S19):
|
class LUXMinerS19(LUXMiner, S19):
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import LUXMiner
|
from pyasic.miners.backends import LUXMiner
|
||||||
from pyasic.miners.device.models import T19
|
from pyasic.miners.models import T19
|
||||||
|
|
||||||
|
|
||||||
class LUXMinerT19(LUXMiner, T19):
|
class LUXMinerT19(LUXMiner, T19):
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import LUXMiner
|
from pyasic.miners.backends import LUXMiner
|
||||||
from pyasic.miners.device.models import S21
|
from pyasic.miners.models import S21
|
||||||
|
|
||||||
|
|
||||||
class LUXMinerS21(LUXMiner, S21):
|
class LUXMinerS21(LUXMiner, S21):
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import LUXMiner
|
from pyasic.miners.backends import LUXMiner
|
||||||
from pyasic.miners.device.models import S9
|
from pyasic.miners.models import S9
|
||||||
|
|
||||||
|
|
||||||
class LUXMinerS9(LUXMiner, S9):
|
class LUXMinerS9(LUXMiner, S9):
|
||||||
|
|||||||
@@ -15,15 +15,7 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import MaraMiner
|
from pyasic.miners.backends import MaraMiner
|
||||||
from pyasic.miners.device.models import (
|
from pyasic.miners.models import S19, S19XP, S19j, S19jNoPIC, S19jPro, S19KPro, S19Pro
|
||||||
S19,
|
|
||||||
S19XP,
|
|
||||||
S19j,
|
|
||||||
S19jNoPIC,
|
|
||||||
S19jPro,
|
|
||||||
S19KPro,
|
|
||||||
S19Pro,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class MaraS19(MaraMiner, S19):
|
class MaraS19(MaraMiner, S19):
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import MaraMiner
|
from pyasic.miners.backends import MaraMiner
|
||||||
from pyasic.miners.device.models import S21
|
from pyasic.miners.models import S21
|
||||||
|
|
||||||
|
|
||||||
class MaraS21(MaraMiner, S21):
|
class MaraS21(MaraMiner, S21):
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import MaraMiner
|
from pyasic.miners.backends import MaraMiner
|
||||||
from pyasic.miners.device.models import T21
|
from pyasic.miners.models import T21
|
||||||
|
|
||||||
|
|
||||||
class MaraT21(MaraMiner, T21):
|
class MaraT21(MaraMiner, T21):
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
# limitations under the License. -
|
# limitations under the License. -
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
from pyasic.miners.backends import VNish
|
from pyasic.miners.backends import VNish
|
||||||
from pyasic.miners.device.models import S17Plus, S17Pro
|
from pyasic.miners.models import S17Plus, S17Pro
|
||||||
|
|
||||||
|
|
||||||
class VNishS17Plus(VNish, S17Plus):
|
class VNishS17Plus(VNish, S17Plus):
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import VNish
|
from pyasic.miners.backends import VNish
|
||||||
from pyasic.miners.device.models import (
|
from pyasic.miners.models import (
|
||||||
S19,
|
S19,
|
||||||
S19XP,
|
S19XP,
|
||||||
S19a,
|
S19a,
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import VNish
|
from pyasic.miners.backends import VNish
|
||||||
from pyasic.miners.device.models import T19
|
from pyasic.miners.models import T19
|
||||||
|
|
||||||
|
|
||||||
class VNishT19(VNish, T19):
|
class VNishT19(VNish, T19):
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import VNish
|
from pyasic.miners.backends import VNish
|
||||||
from pyasic.miners.device.models import L3Plus
|
from pyasic.miners.models import L3Plus
|
||||||
|
|
||||||
|
|
||||||
class VnishL3Plus(VNish, L3Plus):
|
class VnishL3Plus(VNish, L3Plus):
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import VNish
|
from pyasic.miners.backends import VNish
|
||||||
from pyasic.miners.device.models import L7
|
from pyasic.miners.models import L7
|
||||||
|
|
||||||
|
|
||||||
class VnishL7(VNish, L7):
|
class VnishL7(VNish, L7):
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
from pyasic.miners.backends import Auradine
|
from pyasic.miners.backends import Auradine
|
||||||
from pyasic.miners.device.models import AuradineAT1500
|
from pyasic.miners.models import AuradineAT1500
|
||||||
|
|
||||||
|
|
||||||
class AuradineFluxAT1500(AuradineAT1500, Auradine):
|
class AuradineFluxAT1500(AuradineAT1500, Auradine):
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
from pyasic.miners.backends import Auradine
|
from pyasic.miners.backends import Auradine
|
||||||
from pyasic.miners.device.models import AuradineAT2860, AuradineAT2880
|
from pyasic.miners.models import AuradineAT2860, AuradineAT2880
|
||||||
|
|
||||||
|
|
||||||
class AuradineFluxAT2860(AuradineAT2860, Auradine):
|
class AuradineFluxAT2860(AuradineAT2860, Auradine):
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
from pyasic.miners.backends import Auradine
|
from pyasic.miners.backends import Auradine
|
||||||
from pyasic.miners.device.models import AuradineAI2500
|
from pyasic.miners.models import AuradineAI2500
|
||||||
|
|
||||||
|
|
||||||
class AuradineFluxAI2500(AuradineAI2500, Auradine):
|
class AuradineFluxAI2500(AuradineAI2500, Auradine):
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
from pyasic.miners.backends import Auradine
|
from pyasic.miners.backends import Auradine
|
||||||
from pyasic.miners.device.models import AuradineAI3680
|
from pyasic.miners.models import AuradineAI3680
|
||||||
|
|
||||||
|
|
||||||
class AuradineFluxAI3680(AuradineAI3680, Auradine):
|
class AuradineFluxAI3680(AuradineAI3680, Auradine):
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
from pyasic.miners.backends import Auradine
|
from pyasic.miners.backends import Auradine
|
||||||
from pyasic.miners.device.models import AuradineAD2500
|
from pyasic.miners.models import AuradineAD2500
|
||||||
|
|
||||||
|
|
||||||
class AuradineFluxAD2500(AuradineAD2500, Auradine):
|
class AuradineFluxAD2500(AuradineAD2500, Auradine):
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
from pyasic.miners.backends import Auradine
|
from pyasic.miners.backends import Auradine
|
||||||
from pyasic.miners.device.models import AuradineAD3500
|
from pyasic.miners.models import AuradineAD3500
|
||||||
|
|
||||||
|
|
||||||
class AuradineFluxAD3500(AuradineAD3500, Auradine):
|
class AuradineFluxAD3500(AuradineAD3500, Auradine):
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import AvalonMiner
|
from pyasic.miners.backends import AvalonMiner
|
||||||
from pyasic.miners.device.models import Avalon1026
|
from pyasic.miners.models import Avalon1026
|
||||||
|
|
||||||
|
|
||||||
class CGMinerAvalon1026(AvalonMiner, Avalon1026):
|
class CGMinerAvalon1026(AvalonMiner, Avalon1026):
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import AvalonMiner
|
from pyasic.miners.backends import AvalonMiner
|
||||||
from pyasic.miners.device.models import Avalon1047
|
from pyasic.miners.models import Avalon1047
|
||||||
|
|
||||||
|
|
||||||
class CGMinerAvalon1047(AvalonMiner, Avalon1047):
|
class CGMinerAvalon1047(AvalonMiner, Avalon1047):
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import AvalonMiner
|
from pyasic.miners.backends import AvalonMiner
|
||||||
from pyasic.miners.device.models import Avalon1066
|
from pyasic.miners.models import Avalon1066
|
||||||
|
|
||||||
|
|
||||||
class CGMinerAvalon1066(AvalonMiner, Avalon1066):
|
class CGMinerAvalon1066(AvalonMiner, Avalon1066):
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import AvalonMiner
|
from pyasic.miners.backends import AvalonMiner
|
||||||
from pyasic.miners.device.models import Avalon1166Pro
|
from pyasic.miners.models import Avalon1166Pro
|
||||||
|
|
||||||
|
|
||||||
class CGMinerAvalon1166Pro(AvalonMiner, Avalon1166Pro):
|
class CGMinerAvalon1166Pro(AvalonMiner, Avalon1166Pro):
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import AvalonMiner
|
from pyasic.miners.backends import AvalonMiner
|
||||||
from pyasic.miners.device.models import Avalon1246
|
from pyasic.miners.models import Avalon1246
|
||||||
|
|
||||||
|
|
||||||
class CGMinerAvalon1246(AvalonMiner, Avalon1246):
|
class CGMinerAvalon1246(AvalonMiner, Avalon1246):
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import AvalonMiner
|
from pyasic.miners.backends import AvalonMiner
|
||||||
from pyasic.miners.device.models import Avalon721
|
from pyasic.miners.models import Avalon721
|
||||||
|
|
||||||
|
|
||||||
class CGMinerAvalon721(AvalonMiner, Avalon721):
|
class CGMinerAvalon721(AvalonMiner, Avalon721):
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import AvalonMiner
|
from pyasic.miners.backends import AvalonMiner
|
||||||
from pyasic.miners.device.models import Avalon741
|
from pyasic.miners.models import Avalon741
|
||||||
|
|
||||||
|
|
||||||
class CGMinerAvalon741(AvalonMiner, Avalon741):
|
class CGMinerAvalon741(AvalonMiner, Avalon741):
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import AvalonMiner
|
from pyasic.miners.backends import AvalonMiner
|
||||||
from pyasic.miners.device.models import Avalon761
|
from pyasic.miners.models import Avalon761
|
||||||
|
|
||||||
|
|
||||||
class CGMinerAvalon761(AvalonMiner, Avalon761):
|
class CGMinerAvalon761(AvalonMiner, Avalon761):
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import AvalonMiner
|
from pyasic.miners.backends import AvalonMiner
|
||||||
from pyasic.miners.device.models import Avalon821
|
from pyasic.miners.models import Avalon821
|
||||||
|
|
||||||
|
|
||||||
class CGMinerAvalon821(AvalonMiner, Avalon821):
|
class CGMinerAvalon821(AvalonMiner, Avalon821):
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import AvalonMiner
|
from pyasic.miners.backends import AvalonMiner
|
||||||
from pyasic.miners.device.models import Avalon841
|
from pyasic.miners.models import Avalon841
|
||||||
|
|
||||||
|
|
||||||
class CGMinerAvalon841(AvalonMiner, Avalon841):
|
class CGMinerAvalon841(AvalonMiner, Avalon841):
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import AvalonMiner
|
from pyasic.miners.backends import AvalonMiner
|
||||||
from pyasic.miners.device.models import Avalon851
|
from pyasic.miners.models import Avalon851
|
||||||
|
|
||||||
|
|
||||||
class CGMinerAvalon851(AvalonMiner, Avalon851):
|
class CGMinerAvalon851(AvalonMiner, Avalon851):
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import AvalonMiner
|
from pyasic.miners.backends import AvalonMiner
|
||||||
from pyasic.miners.device.models import Avalon921
|
from pyasic.miners.models import Avalon921
|
||||||
|
|
||||||
|
|
||||||
class CGMinerAvalon921(AvalonMiner, Avalon921):
|
class CGMinerAvalon921(AvalonMiner, Avalon921):
|
||||||
|
|||||||
@@ -17,11 +17,12 @@
|
|||||||
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 AlgoHashRate, Fan, HashBoard, HashUnit
|
from pyasic.data import Fan, HashBoard
|
||||||
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
|
||||||
from pyasic.miners.backends.cgminer import CGMiner
|
from pyasic.miners.backends.cgminer import CGMiner
|
||||||
|
from pyasic.miners.base import BaseMiner
|
||||||
from pyasic.miners.data import (
|
from pyasic.miners.data import (
|
||||||
DataFunction,
|
DataFunction,
|
||||||
DataLocations,
|
DataLocations,
|
||||||
@@ -218,9 +219,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 = AlgoHashRate.SHA256(
|
hashboards[board["index"]].hashrate = round(
|
||||||
board["rate_real"], HashUnit.SHA256.GH
|
board["rate_real"] / 1000, 2
|
||||||
).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,9 +274,12 @@ 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"
|
||||||
return AlgoHashRate.SHA256(
|
if rate_unit == "GH":
|
||||||
expected_rate, HashUnit.SHA256.from_str(rate_unit)
|
return round(expected_rate / 1000, 2)
|
||||||
).int(self.algo.unit.default)
|
if rate_unit == "MH":
|
||||||
|
return round(expected_rate / 1000000, 2)
|
||||||
|
else:
|
||||||
|
return round(expected_rate, 2)
|
||||||
except LookupError:
|
except LookupError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -549,9 +553,7 @@ 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 = AlgoHashRate.SHA256(
|
hashboard.hashrate = round(float(hashrate) / 1000, 2)
|
||||||
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:
|
||||||
|
|||||||
@@ -18,8 +18,9 @@ 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 AlgoHashRate, Fan, HashBoard, HashUnit
|
from pyasic.data import Fan, HashBoard
|
||||||
from pyasic.errors import APIError
|
from pyasic.errors import APIError
|
||||||
|
from pyasic.miners.base import BaseMiner
|
||||||
from pyasic.miners.data import (
|
from pyasic.miners.data import (
|
||||||
DataFunction,
|
DataFunction,
|
||||||
DataLocations,
|
DataLocations,
|
||||||
@@ -27,7 +28,6 @@ from pyasic.miners.data import (
|
|||||||
RPCAPICommand,
|
RPCAPICommand,
|
||||||
WebAPICommand,
|
WebAPICommand,
|
||||||
)
|
)
|
||||||
from pyasic.miners.device.firmware import StockFirmware
|
|
||||||
from pyasic.rpc.gcminer import GCMinerRPCAPI
|
from pyasic.rpc.gcminer import GCMinerRPCAPI
|
||||||
from pyasic.web.auradine import AuradineWebAPI
|
from pyasic.web.auradine import AuradineWebAPI
|
||||||
|
|
||||||
@@ -113,7 +113,7 @@ class AuradineLEDCodes(Enum):
|
|||||||
return self.value
|
return self.value
|
||||||
|
|
||||||
|
|
||||||
class Auradine(StockFirmware):
|
class Auradine(BaseMiner):
|
||||||
"""Base handler for Auradine miners"""
|
"""Base handler for Auradine miners"""
|
||||||
|
|
||||||
_rpc_cls = GCMinerRPCAPI
|
_rpc_cls = GCMinerRPCAPI
|
||||||
@@ -245,9 +245,9 @@ class Auradine(StockFirmware):
|
|||||||
|
|
||||||
if rpc_summary is not None:
|
if rpc_summary is not None:
|
||||||
try:
|
try:
|
||||||
return AlgoHashRate.SHA256(
|
return round(
|
||||||
rpc_summary["SUMMARY"][0]["MHS 5s"], HashUnit.SHA256.MH
|
float(float(rpc_summary["SUMMARY"][0]["MHS 5s"]) / 1000000), 2
|
||||||
).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 = AlgoHashRate.SHA256(
|
hashboards[b_id].hashrate = round(
|
||||||
board["MHS 5s"], HashUnit.SHA256.MH
|
float(float(board["MHS 5s"]) / 1000000), 2
|
||||||
).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:
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
import re
|
import re
|
||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
|
|
||||||
from pyasic.data import AlgoHashRate, Fan, HashBoard, HashUnit
|
from pyasic.data import Fan, HashBoard
|
||||||
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,9 +182,7 @@ class AvalonMiner(CGMiner):
|
|||||||
|
|
||||||
if rpc_devs is not None:
|
if rpc_devs is not None:
|
||||||
try:
|
try:
|
||||||
return AlgoHashRate.SHA256(
|
return round(float(rpc_devs["DEVS"][0]["MHS 1m"] / 1000000), 2)
|
||||||
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
|
||||||
|
|
||||||
@@ -215,9 +213,7 @@ class AvalonMiner(CGMiner):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
board_hr = parsed_stats["MGHS"][board]
|
board_hr = parsed_stats["MGHS"][board]
|
||||||
hashboards[board].hashrate = AlgoHashRate.SHA256(
|
hashboards[board].hashrate = round(float(board_hr) / 1000, 2)
|
||||||
board_hr, HashUnit.SHA256.GH
|
|
||||||
).into(self.algo.unit.default)
|
|
||||||
except LookupError:
|
except LookupError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -249,9 +245,7 @@ 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 AlgoHashRate.SHA256(
|
return round(float(parsed_stats["GHSmm"]) / 1000, 2)
|
||||||
parsed_stats["GHSmm"], HashUnit.SHA256.GH
|
|
||||||
).int(self.algo.unit.default)
|
|
||||||
except (IndexError, KeyError, ValueError, TypeError):
|
except (IndexError, KeyError, ValueError, TypeError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -17,10 +17,10 @@
|
|||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
|
|
||||||
from pyasic.config import MinerConfig
|
from pyasic.config import MinerConfig
|
||||||
from pyasic.data import AlgoHashRate, Fan, HashBoard, HashUnit
|
from pyasic.data import Fan, HashBoard
|
||||||
from pyasic.errors import APIError
|
from pyasic.errors import APIError
|
||||||
|
from pyasic.miners.base import BaseMiner
|
||||||
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.rpc.bfgminer import BFGMinerRPCAPI
|
from pyasic.rpc.bfgminer import BFGMinerRPCAPI
|
||||||
|
|
||||||
BFGMINER_DATA_LOC = DataLocations(
|
BFGMINER_DATA_LOC = DataLocations(
|
||||||
@@ -53,7 +53,7 @@ BFGMINER_DATA_LOC = DataLocations(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class BFGMiner(StockFirmware):
|
class BFGMiner(BaseMiner):
|
||||||
"""Base handler for BFGMiner based miners."""
|
"""Base handler for BFGMiner based miners."""
|
||||||
|
|
||||||
_rpc_cls = BFGMinerRPCAPI
|
_rpc_cls = BFGMinerRPCAPI
|
||||||
@@ -115,9 +115,7 @@ class BFGMiner(StockFirmware):
|
|||||||
|
|
||||||
if rpc_summary is not None:
|
if rpc_summary is not None:
|
||||||
try:
|
try:
|
||||||
return AlgoHashRate.SHA256(
|
return round(float(rpc_summary["SUMMARY"][0]["MHS 20s"] / 1000000), 2)
|
||||||
rpc_summary["SUMMARY"][0]["MHS 20s"], HashUnit.SHA256.MH
|
|
||||||
).into(self.algo.unit.default)
|
|
||||||
except (LookupError, ValueError, TypeError):
|
except (LookupError, ValueError, TypeError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -161,9 +159,7 @@ 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 = AlgoHashRate.SHA256(
|
hashboard.hashrate = round(float(hashrate) / 1000, 2)
|
||||||
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:
|
||||||
@@ -222,8 +218,11 @@ 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"
|
||||||
return AlgoHashRate.SHA256(
|
if rate_unit == "GH":
|
||||||
expected_rate, HashUnit.SHA256.from_str(rate_unit)
|
return round(expected_rate / 1000, 2)
|
||||||
).int(self.algo.unit.default)
|
if rate_unit == "MH":
|
||||||
|
return round(expected_rate / 1000000, 2)
|
||||||
|
else:
|
||||||
|
return round(expected_rate, 2)
|
||||||
except LookupError:
|
except LookupError:
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -17,10 +17,10 @@
|
|||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
|
|
||||||
from pyasic.config import MinerConfig
|
from pyasic.config import MinerConfig
|
||||||
from pyasic.data import AlgoHashRate, Fan, HashBoard, HashUnit
|
from pyasic.data import Fan, HashBoard
|
||||||
from pyasic.errors import APIError
|
from pyasic.errors import APIError
|
||||||
|
from pyasic.miners.base import BaseMiner
|
||||||
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.rpc.bmminer import BMMinerRPCAPI
|
from pyasic.rpc.bmminer import BMMinerRPCAPI
|
||||||
|
|
||||||
BMMINER_DATA_LOC = DataLocations(
|
BMMINER_DATA_LOC = DataLocations(
|
||||||
@@ -57,7 +57,7 @@ BMMINER_DATA_LOC = DataLocations(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class BMMiner(StockFirmware):
|
class BMMiner(BaseMiner):
|
||||||
"""Base handler for BMMiner based miners."""
|
"""Base handler for BMMiner based miners."""
|
||||||
|
|
||||||
_rpc_cls = BMMinerRPCAPI
|
_rpc_cls = BMMinerRPCAPI
|
||||||
@@ -119,9 +119,7 @@ class BMMiner(StockFirmware):
|
|||||||
|
|
||||||
if rpc_summary is not None:
|
if rpc_summary is not None:
|
||||||
try:
|
try:
|
||||||
return AlgoHashRate.SHA256(
|
return round(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
|
||||||
|
|
||||||
@@ -178,9 +176,7 @@ 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 = AlgoHashRate.SHA256(
|
hashboard.hashrate = round(float(hashrate) / 1000, 2)
|
||||||
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:
|
||||||
@@ -238,9 +234,12 @@ 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"
|
||||||
return AlgoHashRate.SHA256(
|
if rate_unit == "GH":
|
||||||
expected_rate, HashUnit.SHA256.from_str(rate_unit)
|
return round(expected_rate / 1000, 2)
|
||||||
).int(self.algo.unit.default)
|
if rate_unit == "MH":
|
||||||
|
return round(expected_rate / 1000000, 2)
|
||||||
|
else:
|
||||||
|
return round(expected_rate, 2)
|
||||||
except LookupError:
|
except LookupError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -21,9 +21,10 @@ 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 AlgoHashRate, Fan, HashBoard, HashUnit
|
from pyasic.data import Fan, HashBoard
|
||||||
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.base import BaseMiner
|
||||||
from pyasic.miners.data import (
|
from pyasic.miners.data import (
|
||||||
DataFunction,
|
DataFunction,
|
||||||
DataLocations,
|
DataLocations,
|
||||||
@@ -31,7 +32,6 @@ from pyasic.miners.data import (
|
|||||||
RPCAPICommand,
|
RPCAPICommand,
|
||||||
WebAPICommand,
|
WebAPICommand,
|
||||||
)
|
)
|
||||||
from pyasic.miners.device.firmware import BraiinsOSFirmware
|
|
||||||
from pyasic.rpc.bosminer import BOSMinerRPCAPI
|
from pyasic.rpc.bosminer import BOSMinerRPCAPI
|
||||||
from pyasic.ssh.braiins_os import BOSMinerSSH
|
from pyasic.ssh.braiins_os import BOSMinerSSH
|
||||||
from pyasic.web.braiins_os import BOSerWebAPI, BOSMinerWebAPI
|
from pyasic.web.braiins_os import BOSerWebAPI, BOSMinerWebAPI
|
||||||
@@ -95,7 +95,7 @@ BOSMINER_DATA_LOC = DataLocations(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class BOSMiner(BraiinsOSFirmware):
|
class BOSMiner(BaseMiner):
|
||||||
"""Handler for old versions of BraiinsOS+ (pre-gRPC)"""
|
"""Handler for old versions of BraiinsOS+ (pre-gRPC)"""
|
||||||
|
|
||||||
_rpc_cls = BOSMinerRPCAPI
|
_rpc_cls = BOSMinerRPCAPI
|
||||||
@@ -105,6 +105,8 @@ class BOSMiner(BraiinsOSFirmware):
|
|||||||
_ssh_cls = BOSMinerSSH
|
_ssh_cls = BOSMinerSSH
|
||||||
ssh: BOSMinerSSH
|
ssh: BOSMinerSSH
|
||||||
|
|
||||||
|
firmware = "BOS+"
|
||||||
|
|
||||||
data_locations = BOSMINER_DATA_LOC
|
data_locations = BOSMINER_DATA_LOC
|
||||||
|
|
||||||
supports_shutdown = True
|
supports_shutdown = True
|
||||||
@@ -174,14 +176,11 @@ class BOSMiner(BraiinsOSFirmware):
|
|||||||
self.config = cfg
|
self.config = cfg
|
||||||
except toml.TomlDecodeError as e:
|
except toml.TomlDecodeError as e:
|
||||||
raise APIError("Failed to decode toml when getting config.") from e
|
raise APIError("Failed to decode toml when getting config.") from e
|
||||||
except TypeError as e:
|
|
||||||
raise APIError("Failed to decode toml when getting config.") from e
|
|
||||||
|
|
||||||
return self.config
|
return self.config
|
||||||
|
|
||||||
async def send_config(self, config: MinerConfig, user_suffix: str = None) -> None:
|
async def send_config(self, config: MinerConfig, user_suffix: str = None) -> None:
|
||||||
self.config = config
|
self.config = config
|
||||||
print(config)
|
|
||||||
parsed_cfg = config.as_bosminer(user_suffix=user_suffix)
|
parsed_cfg = config.as_bosminer(user_suffix=user_suffix)
|
||||||
|
|
||||||
toml_conf = toml.dumps(
|
toml_conf = toml.dumps(
|
||||||
@@ -202,7 +201,9 @@ class BOSMiner(BraiinsOSFirmware):
|
|||||||
|
|
||||||
async with conn:
|
async with conn:
|
||||||
await conn.run("/etc/init.d/bosminer stop")
|
await conn.run("/etc/init.d/bosminer stop")
|
||||||
await conn.run("echo '" + toml_conf + "' > /etc/bosminer.toml")
|
async with conn.start_sftp_client() as sftp:
|
||||||
|
async with sftp.open("/etc/bosminer.toml", "w+") as file:
|
||||||
|
await file.write(toml_conf)
|
||||||
await conn.run("/etc/init.d/bosminer start")
|
await conn.run("/etc/init.d/bosminer start")
|
||||||
|
|
||||||
async def set_power_limit(self, wattage: int) -> bool:
|
async def set_power_limit(self, wattage: int) -> bool:
|
||||||
@@ -350,9 +351,7 @@ class BOSMiner(BraiinsOSFirmware):
|
|||||||
|
|
||||||
if rpc_summary is not None:
|
if rpc_summary is not None:
|
||||||
try:
|
try:
|
||||||
return AlgoHashRate.SHA256(
|
return round(float(rpc_summary["SUMMARY"][0]["MHS 1m"] / 1000000), 2)
|
||||||
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
|
||||||
|
|
||||||
@@ -422,9 +421,8 @@ class BOSMiner(BraiinsOSFirmware):
|
|||||||
|
|
||||||
for board in rpc_devs["DEVS"]:
|
for board in rpc_devs["DEVS"]:
|
||||||
_id = board["ID"] - offset
|
_id = board["ID"] - offset
|
||||||
hashboards[_id].hashrate = AlgoHashRate.SHA256(
|
hashrate = round(float(board["MHS 1m"] / 1000000), 2)
|
||||||
board["MHS 1m"], HashUnit.SHA256.MH
|
hashboards[_id].hashrate = hashrate
|
||||||
).into(self.algo.unit.default)
|
|
||||||
except (IndexError, KeyError):
|
except (IndexError, KeyError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -532,12 +530,11 @@ 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 AlgoHashRate.SHA256(0)
|
return 0
|
||||||
else:
|
else:
|
||||||
return AlgoHashRate.SHA256(
|
return round(
|
||||||
(sum(hr_list) / len(hr_list)) * self.expected_hashboards
|
(sum(hr_list) / len(hr_list)) * self.expected_hashboards, 2
|
||||||
)
|
)
|
||||||
except (IndexError, KeyError):
|
except (IndexError, KeyError):
|
||||||
pass
|
pass
|
||||||
@@ -637,7 +634,7 @@ BOSER_DATA_LOC = DataLocations(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class BOSer(BraiinsOSFirmware):
|
class BOSer(BaseMiner):
|
||||||
"""Handler for new versions of BraiinsOS+ (post-gRPC)"""
|
"""Handler for new versions of BraiinsOS+ (post-gRPC)"""
|
||||||
|
|
||||||
_rpc_cls = BOSMinerRPCAPI
|
_rpc_cls = BOSMinerRPCAPI
|
||||||
@@ -788,9 +785,7 @@ class BOSer(BraiinsOSFirmware):
|
|||||||
|
|
||||||
if rpc_summary is not None:
|
if rpc_summary is not None:
|
||||||
try:
|
try:
|
||||||
return AlgoHashRate.SHA256(
|
return round(float(rpc_summary["SUMMARY"][0]["MHS 1m"] / 1000000), 2)
|
||||||
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
|
||||||
|
|
||||||
@@ -805,10 +800,7 @@ class BOSer(BraiinsOSFirmware):
|
|||||||
|
|
||||||
if grpc_miner_details is not None:
|
if grpc_miner_details is not None:
|
||||||
try:
|
try:
|
||||||
return AlgoHashRate.SHA256(
|
return grpc_miner_details["stickerHashrate"]["gigahashPerSecond"] / 1000
|
||||||
grpc_miner_details["stickerHashrate"]["gigahashPerSecond"],
|
|
||||||
HashUnit.SHA256.GH,
|
|
||||||
).into(self.algo.unit.default)
|
|
||||||
except LookupError:
|
except LookupError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -837,12 +829,13 @@ 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 = AlgoHashRate.SHA256(
|
hashboards[idx].hashrate = round(
|
||||||
board["stats"]["realHashrate"]["last5S"][
|
board["stats"]["realHashrate"]["last5S"][
|
||||||
"gigahashPerSecond"
|
"gigahashPerSecond"
|
||||||
],
|
]
|
||||||
HashUnit.SHA256.GH,
|
/ 1000,
|
||||||
).into(self.algo.unit.default)
|
2,
|
||||||
|
)
|
||||||
hashboards[idx].missing = False
|
hashboards[idx].missing = False
|
||||||
|
|
||||||
return hashboards
|
return hashboards
|
||||||
|
|||||||
@@ -18,11 +18,11 @@ 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 AlgoHashRate, Fan, HashBoard, HashUnit
|
from pyasic.data import Fan, HashBoard
|
||||||
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.base import BaseMiner
|
||||||
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.rpc.btminer import BTMinerRPCAPI
|
from pyasic.rpc.btminer import BTMinerRPCAPI
|
||||||
|
|
||||||
BTMINER_DATA_LOC = DataLocations(
|
BTMINER_DATA_LOC = DataLocations(
|
||||||
@@ -110,7 +110,7 @@ BTMINER_DATA_LOC = DataLocations(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class BTMiner(StockFirmware):
|
class BTMiner(BaseMiner):
|
||||||
"""Base handler for BTMiner based miners."""
|
"""Base handler for BTMiner based miners."""
|
||||||
|
|
||||||
_rpc_cls = BTMinerRPCAPI
|
_rpc_cls = BTMinerRPCAPI
|
||||||
@@ -395,9 +395,7 @@ class BTMiner(StockFirmware):
|
|||||||
|
|
||||||
if rpc_summary is not None:
|
if rpc_summary is not None:
|
||||||
try:
|
try:
|
||||||
return AlgoHashRate.SHA256(
|
return round(float(rpc_summary["SUMMARY"][0]["MHS 1m"] / 1000000), 2)
|
||||||
rpc_summary["SUMMARY"][0]["MHS 1m"], HashUnit.SHA256.MH
|
|
||||||
).into(self.algo.unit.default)
|
|
||||||
except LookupError:
|
except LookupError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -425,9 +423,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 = AlgoHashRate.SHA256(
|
hashboards[board["ASC"]].hashrate = round(
|
||||||
board["MHS 1m"], HashUnit.SHA256.MH
|
float(board["MHS 1m"] / 1000000), 2
|
||||||
).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
|
||||||
@@ -573,10 +571,7 @@ 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 AlgoHashRate.SHA256(
|
return round(expected_hashrate / 1000, 2)
|
||||||
expected_hashrate, HashUnit.SHA256.GH
|
|
||||||
).int(self.algo.unit.default)
|
|
||||||
|
|
||||||
except LookupError:
|
except LookupError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -17,10 +17,9 @@
|
|||||||
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.base import BaseMiner
|
||||||
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.rpc.cgminer import CGMinerRPCAPI
|
from pyasic.rpc.cgminer import CGMinerRPCAPI
|
||||||
|
|
||||||
CGMINER_DATA_LOC = DataLocations(
|
CGMINER_DATA_LOC = DataLocations(
|
||||||
@@ -57,7 +56,7 @@ CGMINER_DATA_LOC = DataLocations(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class CGMiner(StockFirmware):
|
class CGMiner(BaseMiner):
|
||||||
"""Base handler for CGMiner based miners"""
|
"""Base handler for CGMiner based miners"""
|
||||||
|
|
||||||
_rpc_cls = CGMinerRPCAPI
|
_rpc_cls = CGMinerRPCAPI
|
||||||
@@ -118,9 +117,9 @@ class CGMiner(StockFirmware):
|
|||||||
|
|
||||||
if rpc_summary is not None:
|
if rpc_summary is not None:
|
||||||
try:
|
try:
|
||||||
return AlgoHashRate.SHA256(
|
return round(
|
||||||
rpc_summary["SUMMARY"][0]["GHS 5s"], HashUnit.SHA256.GH
|
float(float(rpc_summary["SUMMARY"][0]["GHS 5s"]) / 1000), 2
|
||||||
).into(self.algo.unit.default)
|
)
|
||||||
except (LookupError, ValueError, TypeError):
|
except (LookupError, ValueError, TypeError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -17,12 +17,12 @@
|
|||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
|
|
||||||
from pyasic.config import MinerConfig
|
from pyasic.config import MinerConfig
|
||||||
from pyasic.data import AlgoHashRate, Fan, HashBoard, HashUnit
|
from pyasic.data import Fan, HashBoard
|
||||||
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
|
||||||
|
from pyasic.miners.base import BaseMiner
|
||||||
from pyasic.miners.data import DataFunction, DataLocations, DataOptions, WebAPICommand
|
from pyasic.miners.data import DataFunction, DataLocations, DataOptions, WebAPICommand
|
||||||
from pyasic.miners.device.firmware import ePICFirmware
|
|
||||||
from pyasic.web.epic import ePICWebAPI
|
from pyasic.web.epic import ePICWebAPI
|
||||||
|
|
||||||
EPIC_DATA_LOC = DataLocations(
|
EPIC_DATA_LOC = DataLocations(
|
||||||
@@ -58,10 +58,6 @@ EPIC_DATA_LOC = DataLocations(
|
|||||||
"_get_wattage",
|
"_get_wattage",
|
||||||
[WebAPICommand("web_summary", "summary")],
|
[WebAPICommand("web_summary", "summary")],
|
||||||
),
|
),
|
||||||
str(DataOptions.VOLTAGE): DataFunction(
|
|
||||||
"_get_voltage",
|
|
||||||
[WebAPICommand("web_summary", "summary")],
|
|
||||||
),
|
|
||||||
str(DataOptions.FANS): DataFunction(
|
str(DataOptions.FANS): DataFunction(
|
||||||
"_get_fans",
|
"_get_fans",
|
||||||
[WebAPICommand("web_summary", "summary")],
|
[WebAPICommand("web_summary", "summary")],
|
||||||
@@ -86,12 +82,14 @@ EPIC_DATA_LOC = DataLocations(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class ePIC(ePICFirmware):
|
class ePIC(BaseMiner):
|
||||||
"""Handler for miners with the ePIC board"""
|
"""Handler for miners with the ePIC board"""
|
||||||
|
|
||||||
_web_cls = ePICWebAPI
|
_web_cls = ePICWebAPI
|
||||||
web: ePICWebAPI
|
web: ePICWebAPI
|
||||||
|
|
||||||
|
firmware = "ePIC"
|
||||||
|
|
||||||
data_locations = EPIC_DATA_LOC
|
data_locations = EPIC_DATA_LOC
|
||||||
|
|
||||||
supports_shutdown = True
|
supports_shutdown = True
|
||||||
@@ -121,7 +119,6 @@ class ePIC(ePICFirmware):
|
|||||||
# Temps
|
# Temps
|
||||||
if not conf.get("temps", {}) == {}:
|
if not conf.get("temps", {}) == {}:
|
||||||
await self.web.set_shutdown_temp(conf["temps"]["shutdown"])
|
await self.web.set_shutdown_temp(conf["temps"]["shutdown"])
|
||||||
await self.web.set_critical_temp(conf["temps"]["critical"])
|
|
||||||
# Fans
|
# Fans
|
||||||
# set with sub-keys instead of conf["fans"] because sometimes both can be set
|
# set with sub-keys instead of conf["fans"] because sometimes both can be set
|
||||||
if not conf["fans"].get("Manual", {}) == {}:
|
if not conf["fans"].get("Manual", {}) == {}:
|
||||||
@@ -132,7 +129,7 @@ class ePIC(ePICFirmware):
|
|||||||
# Mining Mode -- Need to handle that you may not be able to change while miner is tuning
|
# Mining Mode -- Need to handle that you may not be able to change while miner is tuning
|
||||||
if conf["ptune"].get("enabled", True):
|
if conf["ptune"].get("enabled", True):
|
||||||
await self.web.set_ptune_enable(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
|
## Pools
|
||||||
await self.web.set_pools(conf["pools"])
|
await self.web.set_pools(conf["pools"])
|
||||||
@@ -219,20 +216,6 @@ class ePIC(ePICFirmware):
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
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]:
|
async def _get_hashrate(self, web_summary: dict = None) -> Optional[float]:
|
||||||
if web_summary is None:
|
if web_summary is None:
|
||||||
try:
|
try:
|
||||||
@@ -246,9 +229,7 @@ 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 AlgoHashRate.SHA256(hashrate, HashUnit.SHA256.MH).into(
|
return round(float(float(hashrate / 1000000)), 2)
|
||||||
HashUnit.SHA256.TH
|
|
||||||
)
|
|
||||||
except (LookupError, ValueError, TypeError):
|
except (LookupError, ValueError, TypeError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -270,9 +251,7 @@ class ePIC(ePICFirmware):
|
|||||||
ideal = hb["Hashrate"][1] / 100
|
ideal = hb["Hashrate"][1] / 100
|
||||||
|
|
||||||
hashrate += hb["Hashrate"][0] / ideal
|
hashrate += hb["Hashrate"][0] / ideal
|
||||||
return AlgoHashRate.SHA256(hashrate, HashUnit.SHA256.GH).int(
|
return round(float(float(hashrate / 1000000)), 2)
|
||||||
self.algo.unit.default
|
|
||||||
)
|
|
||||||
except (LookupError, ValueError, TypeError):
|
except (LookupError, ValueError, TypeError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -317,7 +296,7 @@ class ePIC(ePICFirmware):
|
|||||||
except APIError:
|
except APIError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if web_capabilities is None:
|
if web_capabilities is not None:
|
||||||
try:
|
try:
|
||||||
web_capabilities = await self.web.capabilities()
|
web_capabilities = await self.web.capabilities()
|
||||||
except APIError:
|
except APIError:
|
||||||
@@ -327,26 +306,13 @@ class ePIC(ePICFirmware):
|
|||||||
HashBoard(slot=i, expected_chips=self.expected_chips)
|
HashBoard(slot=i, expected_chips=self.expected_chips)
|
||||||
for i in range(self.expected_hashboards)
|
for i in range(self.expected_hashboards)
|
||||||
]
|
]
|
||||||
if web_summary is not None and web_capabilities is not None:
|
|
||||||
if web_summary.get("HBs") is not None:
|
if web_summary.get("HBs") is not None:
|
||||||
for hb in web_summary["HBs"]:
|
for hb in web_summary["HBs"]:
|
||||||
if web_capabilities.get("Performance Estimator") is not None:
|
num_of_chips = web_capabilities["Performance Estimator"]["Chip Count"]
|
||||||
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]
|
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 = AlgoHashRate.SHA256(
|
hb_list[hb["Index"]].hashrate = round(hashrate / 1000000, 2)
|
||||||
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
|
||||||
|
|||||||
@@ -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 AlgoHashRate, HashBoard, HashUnit
|
from pyasic.data import HashBoard
|
||||||
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 = AlgoHashRate.SHA256(
|
hashboards[b_id].hashrate = round(
|
||||||
board["MHS 20s"], HashUnit.SHA256.MH
|
board["MHS 20s"] / 1000000, 2
|
||||||
).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:
|
||||||
|
|||||||
@@ -15,8 +15,7 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import BMMiner
|
from pyasic.miners.backends import BMMiner
|
||||||
from pyasic.miners.device.firmware import HiveonFirmware
|
|
||||||
|
|
||||||
|
|
||||||
class Hiveon(BMMiner, HiveonFirmware):
|
class Hiveon(BMMiner):
|
||||||
pass
|
firmware = "Hive"
|
||||||
|
|||||||
@@ -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 AlgoHashRate, Fan, HashBoard, HashUnit
|
from pyasic.data import Fan, HashBoard
|
||||||
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,21 +182,20 @@ 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 AlgoHashRate.SHA256(
|
return round(
|
||||||
web_get_all["total_hash"]["Hash Rate H"], HashUnit.SHA256.H
|
float(web_get_all["total_hash"]["Hash Rate H"] / 1000000000000),
|
||||||
).into(self.algo.unit.default)
|
2,
|
||||||
|
)
|
||||||
elif "Hash Rate" in web_get_all["total_hash"].keys():
|
elif "Hash Rate" in web_get_all["total_hash"].keys():
|
||||||
return AlgoHashRate.SHA256(
|
return round(
|
||||||
web_get_all["total_hash"]["Hash Rate"], HashUnit.SHA256.MH
|
float(web_get_all["total_hash"]["Hash Rate"] / 1000000), 5
|
||||||
).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 AlgoHashRate.SHA256(
|
return round(float(rpc_summary["SUMMARY"][0]["MHS 1m"] / 1000000), 2)
|
||||||
rpc_summary["SUMMARY"][0]["MHS 1m"], HashUnit.SHA256.MH
|
|
||||||
).into(self.algo.unit.default)
|
|
||||||
except (KeyError, IndexError):
|
except (KeyError, IndexError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -248,9 +247,9 @@ class Innosilicon(CGMiner):
|
|||||||
|
|
||||||
hashrate = board.get("Hash Rate H")
|
hashrate = board.get("Hash Rate H")
|
||||||
if hashrate:
|
if hashrate:
|
||||||
hashboards[idx].hashrate = AlgoHashRate.SHA256(
|
hashboards[idx].hashrate = round(
|
||||||
hashrate, HashUnit.SHA256.H
|
hashrate / 1000000000000, 2
|
||||||
).into(self.algo.unit.default)
|
)
|
||||||
|
|
||||||
chip_temp = board.get("Temp max")
|
chip_temp = board.get("Temp max")
|
||||||
if chip_temp:
|
if chip_temp:
|
||||||
|
|||||||
@@ -16,10 +16,10 @@
|
|||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
|
|
||||||
from pyasic.config import MinerConfig
|
from pyasic.config import MinerConfig
|
||||||
from pyasic.data import AlgoHashRate, Fan, HashBoard, HashUnit
|
from pyasic.data import Fan, HashBoard
|
||||||
from pyasic.errors import APIError
|
from pyasic.errors import APIError
|
||||||
|
from pyasic.miners.base import BaseMiner
|
||||||
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.rpc.luxminer import LUXMinerRPCAPI
|
from pyasic.rpc.luxminer import LUXMinerRPCAPI
|
||||||
|
|
||||||
LUXMINER_DATA_LOC = DataLocations(
|
LUXMINER_DATA_LOC = DataLocations(
|
||||||
@@ -55,12 +55,14 @@ LUXMINER_DATA_LOC = DataLocations(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class LUXMiner(LuxOSFirmware):
|
class LUXMiner(BaseMiner):
|
||||||
"""Handler for LuxOS miners"""
|
"""Handler for LuxOS miners"""
|
||||||
|
|
||||||
_rpc_cls = LUXMinerRPCAPI
|
_rpc_cls = LUXMinerRPCAPI
|
||||||
rpc: LUXMinerRPCAPI
|
rpc: LUXMinerRPCAPI
|
||||||
|
|
||||||
|
firmware = "LuxOS"
|
||||||
|
|
||||||
data_locations = LUXMINER_DATA_LOC
|
data_locations = LUXMINER_DATA_LOC
|
||||||
|
|
||||||
async def _get_session(self) -> Optional[str]:
|
async def _get_session(self) -> Optional[str]:
|
||||||
@@ -171,9 +173,7 @@ class LUXMiner(LuxOSFirmware):
|
|||||||
|
|
||||||
if rpc_summary is not None:
|
if rpc_summary is not None:
|
||||||
try:
|
try:
|
||||||
return AlgoHashRate.SHA256(
|
return round(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
|
||||||
|
|
||||||
@@ -217,9 +217,7 @@ 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 = AlgoHashRate.SHA256(
|
hashboard.hashrate = round(float(hashrate) / 1000, 2)
|
||||||
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:
|
||||||
@@ -277,9 +275,12 @@ 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"
|
||||||
return AlgoHashRate.SHA256(
|
if rate_unit == "GH":
|
||||||
expected_rate, HashUnit.SHA256.from_str(rate_unit)
|
return round(expected_rate / 1000, 2)
|
||||||
).int(self.algo.unit.default)
|
if rate_unit == "MH":
|
||||||
|
return round(expected_rate / 1000000, 2)
|
||||||
|
else:
|
||||||
|
return round(expected_rate, 2)
|
||||||
except LookupError:
|
except LookupError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -1,119 +1,77 @@
|
|||||||
from typing import List, Optional
|
from typing import Optional
|
||||||
|
|
||||||
from pyasic import MinerConfig
|
|
||||||
from pyasic.config import MiningModeConfig
|
|
||||||
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.backends import AntminerModern
|
||||||
from pyasic.miners.device.firmware import MaraFirmware
|
from pyasic.miners.data import (
|
||||||
from pyasic.misc import merge_dicts
|
DataFunction,
|
||||||
|
DataLocations,
|
||||||
|
DataOptions,
|
||||||
|
RPCAPICommand,
|
||||||
|
WebAPICommand,
|
||||||
|
)
|
||||||
from pyasic.web.marathon import MaraWebAPI
|
from pyasic.web.marathon import MaraWebAPI
|
||||||
|
|
||||||
MARA_DATA_LOC = DataLocations(
|
MARA_DATA_LOC = DataLocations(
|
||||||
**{
|
**{
|
||||||
str(DataOptions.MAC): DataFunction(
|
str(DataOptions.MAC): DataFunction(
|
||||||
"_get_mac",
|
"_get_mac",
|
||||||
[WebAPICommand("web_overview", "overview")],
|
[WebAPICommand("web_get_system_info", "get_system_info")],
|
||||||
|
),
|
||||||
|
str(DataOptions.API_VERSION): DataFunction(
|
||||||
|
"_get_api_ver",
|
||||||
|
[RPCAPICommand("rpc_version", "version")],
|
||||||
),
|
),
|
||||||
str(DataOptions.FW_VERSION): DataFunction(
|
str(DataOptions.FW_VERSION): DataFunction(
|
||||||
"_get_fw_ver",
|
"_get_fw_ver",
|
||||||
[WebAPICommand("web_overview", "overview")],
|
[RPCAPICommand("rpc_version", "version")],
|
||||||
),
|
),
|
||||||
str(DataOptions.HOSTNAME): DataFunction(
|
str(DataOptions.HOSTNAME): DataFunction(
|
||||||
"_get_hostname",
|
"_get_hostname",
|
||||||
[WebAPICommand("web_network_config", "network_config")],
|
[WebAPICommand("web_get_system_info", "get_system_info")],
|
||||||
),
|
),
|
||||||
str(DataOptions.HASHRATE): DataFunction(
|
str(DataOptions.HASHRATE): DataFunction(
|
||||||
"_get_hashrate",
|
"_get_hashrate",
|
||||||
[WebAPICommand("web_brief", "brief")],
|
[RPCAPICommand("rpc_summary", "summary")],
|
||||||
),
|
),
|
||||||
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
|
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
|
||||||
"_get_expected_hashrate",
|
"_get_expected_hashrate",
|
||||||
[WebAPICommand("web_brief", "brief")],
|
[RPCAPICommand("rpc_stats", "stats")],
|
||||||
),
|
|
||||||
str(DataOptions.HASHBOARDS): DataFunction(
|
|
||||||
"_get_hashboards",
|
|
||||||
[WebAPICommand("web_hashboards", "hashboards")],
|
|
||||||
),
|
|
||||||
str(DataOptions.WATTAGE): DataFunction(
|
|
||||||
"_get_wattage",
|
|
||||||
[WebAPICommand("web_brief", "brief")],
|
|
||||||
),
|
|
||||||
str(DataOptions.WATTAGE_LIMIT): DataFunction(
|
|
||||||
"_get_wattage_limit",
|
|
||||||
[WebAPICommand("web_miner_config", "miner_config")],
|
|
||||||
),
|
),
|
||||||
str(DataOptions.FANS): DataFunction(
|
str(DataOptions.FANS): DataFunction(
|
||||||
"_get_fans",
|
"_get_fans",
|
||||||
[WebAPICommand("web_fans", "fans")],
|
[RPCAPICommand("rpc_stats", "stats")],
|
||||||
|
),
|
||||||
|
str(DataOptions.ERRORS): DataFunction(
|
||||||
|
"_get_errors",
|
||||||
|
[WebAPICommand("web_summary", "summary")],
|
||||||
),
|
),
|
||||||
str(DataOptions.FAULT_LIGHT): DataFunction(
|
str(DataOptions.FAULT_LIGHT): DataFunction(
|
||||||
"_get_fault_light",
|
"_get_fault_light",
|
||||||
[WebAPICommand("web_locate_miner", "locate_miner")],
|
[WebAPICommand("web_get_blink_status", "get_blink_status")],
|
||||||
),
|
),
|
||||||
str(DataOptions.IS_MINING): DataFunction(
|
str(DataOptions.IS_MINING): DataFunction(
|
||||||
"_is_mining",
|
"_is_mining",
|
||||||
[WebAPICommand("web_brief", "brief")],
|
[WebAPICommand("web_get_conf", "get_miner_conf")],
|
||||||
),
|
),
|
||||||
str(DataOptions.UPTIME): DataFunction(
|
str(DataOptions.UPTIME): DataFunction(
|
||||||
"_get_uptime",
|
"_get_uptime",
|
||||||
|
[RPCAPICommand("rpc_stats", "stats")],
|
||||||
|
),
|
||||||
|
str(DataOptions.WATTAGE): DataFunction(
|
||||||
|
"_get_wattage",
|
||||||
[WebAPICommand("web_brief", "brief")],
|
[WebAPICommand("web_brief", "brief")],
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class MaraMiner(MaraFirmware):
|
class MaraMiner(AntminerModern):
|
||||||
_web_cls = MaraWebAPI
|
_web_cls = MaraWebAPI
|
||||||
web: MaraWebAPI
|
web: MaraWebAPI
|
||||||
|
|
||||||
data_locations = MARA_DATA_LOC
|
data_locations = MARA_DATA_LOC
|
||||||
|
|
||||||
async def fault_light_off(self) -> bool:
|
firmware = "MaraFW"
|
||||||
res = await self.web.set_locate_miner(blinking=False)
|
|
||||||
return res.get("blinking") is False
|
|
||||||
|
|
||||||
async def fault_light_on(self) -> bool:
|
|
||||||
res = await self.web.set_locate_miner(blinking=True)
|
|
||||||
return res.get("blinking") is True
|
|
||||||
|
|
||||||
async def get_config(self) -> MinerConfig:
|
|
||||||
data = await self.web.get_miner_config()
|
|
||||||
if data:
|
|
||||||
self.config = MinerConfig.from_mara(data)
|
|
||||||
return self.config
|
|
||||||
|
|
||||||
async def send_config(self, config: MinerConfig, user_suffix: str = None) -> None:
|
|
||||||
data = await self.web.get_miner_config()
|
|
||||||
cfg_data = config.as_mara(user_suffix=user_suffix)
|
|
||||||
merged_cfg = merge_dicts(data, cfg_data)
|
|
||||||
await self.web.set_miner_config(**merged_cfg)
|
|
||||||
|
|
||||||
async def set_power_limit(self, wattage: int) -> bool:
|
|
||||||
cfg = await self.get_config()
|
|
||||||
cfg.mining_mode = MiningModeConfig.power_tuning(wattage)
|
|
||||||
await self.send_config(cfg)
|
|
||||||
return True
|
|
||||||
|
|
||||||
async def stop_mining(self) -> bool:
|
|
||||||
data = await self.web.get_miner_config()
|
|
||||||
data["mode"]["work-mode-selector"] = "Sleep"
|
|
||||||
await self.web.set_miner_config(**data)
|
|
||||||
return True
|
|
||||||
|
|
||||||
async def resume_mining(self) -> bool:
|
|
||||||
data = await self.web.get_miner_config()
|
|
||||||
data["mode"]["work-mode-selector"] = "Auto"
|
|
||||||
await self.web.set_miner_config(**data)
|
|
||||||
return True
|
|
||||||
|
|
||||||
async def reboot(self) -> bool:
|
|
||||||
await self.web.reboot()
|
|
||||||
return True
|
|
||||||
|
|
||||||
async def restart_backend(self) -> bool:
|
|
||||||
await self.web.reload()
|
|
||||||
return True
|
|
||||||
|
|
||||||
async def _get_wattage(self, web_brief: dict = None) -> Optional[int]:
|
async def _get_wattage(self, web_brief: dict = None) -> Optional[int]:
|
||||||
if web_brief is None:
|
if web_brief is None:
|
||||||
@@ -124,179 +82,6 @@ class MaraMiner(MaraFirmware):
|
|||||||
|
|
||||||
if web_brief is not None:
|
if web_brief is not None:
|
||||||
try:
|
try:
|
||||||
return round(web_brief["power_consumption_estimated"])
|
return web_brief["power_consumption_estimated"]
|
||||||
except LookupError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
async def _is_mining(self, web_brief: dict = None) -> Optional[bool]:
|
|
||||||
if web_brief is None:
|
|
||||||
try:
|
|
||||||
web_brief = await self.web.brief()
|
|
||||||
except APIError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if web_brief is not None:
|
|
||||||
try:
|
|
||||||
return web_brief["status"] == "Mining"
|
|
||||||
except LookupError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
async def _get_uptime(self, web_brief: dict = None) -> Optional[int]:
|
|
||||||
if web_brief is None:
|
|
||||||
try:
|
|
||||||
web_brief = await self.web.brief()
|
|
||||||
except APIError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if web_brief is not None:
|
|
||||||
try:
|
|
||||||
return web_brief["elapsed"]
|
|
||||||
except LookupError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
async def _get_hashboards(self, web_hashboards: dict = None) -> List[HashBoard]:
|
|
||||||
hashboards = [
|
|
||||||
HashBoard(slot=i, expected_chips=self.expected_chips)
|
|
||||||
for i in range(self.expected_hashboards)
|
|
||||||
]
|
|
||||||
|
|
||||||
if web_hashboards is None:
|
|
||||||
try:
|
|
||||||
web_hashboards = await self.web.hashboards()
|
|
||||||
except APIError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if web_hashboards is not None:
|
|
||||||
try:
|
|
||||||
for hb in web_hashboards["hashboards"]:
|
|
||||||
idx = hb["index"]
|
|
||||||
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
|
|
||||||
)
|
|
||||||
hashboards[idx].chip_temp = round(
|
|
||||||
sum(hb["temperature_chip"]) / len(hb["temperature_chip"]), 2
|
|
||||||
)
|
|
||||||
hashboards[idx].chips = hb["asic_num"]
|
|
||||||
hashboards[idx].serial_number = hb["serial_number"]
|
|
||||||
hashboards[idx].missing = False
|
|
||||||
except LookupError:
|
|
||||||
pass
|
|
||||||
return hashboards
|
|
||||||
|
|
||||||
async def _get_mac(self, web_overview: dict = None) -> Optional[str]:
|
|
||||||
if web_overview is None:
|
|
||||||
try:
|
|
||||||
web_overview = await self.web.overview()
|
|
||||||
except APIError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if web_overview is not None:
|
|
||||||
try:
|
|
||||||
return web_overview["mac"].upper()
|
|
||||||
except LookupError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
async def _get_fw_ver(self, web_overview: dict = None) -> Optional[str]:
|
|
||||||
if web_overview is None:
|
|
||||||
try:
|
|
||||||
web_overview = await self.web.overview()
|
|
||||||
except APIError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if web_overview is not None:
|
|
||||||
try:
|
|
||||||
return web_overview["version_firmware"]
|
|
||||||
except LookupError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
async def _get_hostname(self, web_network_config: dict = None) -> Optional[str]:
|
|
||||||
if web_network_config is None:
|
|
||||||
try:
|
|
||||||
web_network_config = await self.web.get_network_config()
|
|
||||||
except APIError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if web_network_config is not None:
|
|
||||||
try:
|
|
||||||
return web_network_config["hostname"]
|
|
||||||
except LookupError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
async def _get_hashrate(self, web_brief: dict = None) -> Optional[float]:
|
|
||||||
if web_brief is None:
|
|
||||||
try:
|
|
||||||
web_brief = await self.web.brief()
|
|
||||||
except APIError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if web_brief is not None:
|
|
||||||
try:
|
|
||||||
return AlgoHashRate.SHA256(
|
|
||||||
web_brief["hashrate_realtime"], HashUnit.SHA256.TH
|
|
||||||
).into(self.algo.unit.default)
|
|
||||||
except LookupError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
async def _get_fans(self, web_fans: dict = None) -> List[Fan]:
|
|
||||||
if web_fans is None:
|
|
||||||
try:
|
|
||||||
web_fans = await self.web.fans()
|
|
||||||
except APIError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if web_fans is not None:
|
|
||||||
fans = []
|
|
||||||
for n in range(self.expected_fans):
|
|
||||||
try:
|
|
||||||
fans.append(Fan(web_fans["fans"][n]["current_speed"]))
|
|
||||||
except (IndexError, KeyError):
|
|
||||||
pass
|
|
||||||
return fans
|
|
||||||
return [Fan() for _ in range(self.expected_fans)]
|
|
||||||
|
|
||||||
async def _get_fault_light(self, web_locate_miner: dict = None) -> bool:
|
|
||||||
if web_locate_miner is None:
|
|
||||||
try:
|
|
||||||
web_locate_miner = await self.web.get_locate_miner()
|
|
||||||
except APIError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if web_locate_miner is not None:
|
|
||||||
try:
|
|
||||||
return web_locate_miner["blinking"]
|
|
||||||
except LookupError:
|
|
||||||
pass
|
|
||||||
return False
|
|
||||||
|
|
||||||
async def _get_expected_hashrate(self, web_brief: dict = None) -> Optional[float]:
|
|
||||||
if web_brief is None:
|
|
||||||
try:
|
|
||||||
web_brief = await self.web.brief()
|
|
||||||
except APIError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if web_brief is not None:
|
|
||||||
try:
|
|
||||||
return AlgoHashRate.SHA256(
|
|
||||||
web_brief["hashrate_ideal"], HashUnit.SHA256.GH
|
|
||||||
).int(self.algo.unit.default)
|
|
||||||
except LookupError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
async def _get_wattage_limit(
|
|
||||||
self, web_miner_config: dict = None
|
|
||||||
) -> Optional[float]:
|
|
||||||
if web_miner_config is None:
|
|
||||||
try:
|
|
||||||
web_miner_config = await self.web.get_miner_config()
|
|
||||||
except APIError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if web_miner_config is not None:
|
|
||||||
try:
|
|
||||||
return web_miner_config["mode"]["concorde"]["power-target"]
|
|
||||||
except LookupError:
|
except LookupError:
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
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 (
|
||||||
@@ -27,7 +26,6 @@ from pyasic.miners.data import (
|
|||||||
RPCAPICommand,
|
RPCAPICommand,
|
||||||
WebAPICommand,
|
WebAPICommand,
|
||||||
)
|
)
|
||||||
from pyasic.miners.device.firmware import VNishFirmware
|
|
||||||
from pyasic.web.vnish import VNishWebAPI
|
from pyasic.web.vnish import VNishWebAPI
|
||||||
|
|
||||||
VNISH_DATA_LOC = DataLocations(
|
VNISH_DATA_LOC = DataLocations(
|
||||||
@@ -84,7 +82,7 @@ VNISH_DATA_LOC = DataLocations(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class VNish(BMMiner, VNishFirmware):
|
class VNish(BMMiner):
|
||||||
"""Handler for VNish miners"""
|
"""Handler for VNish miners"""
|
||||||
|
|
||||||
_web_cls = VNishWebAPI
|
_web_cls = VNishWebAPI
|
||||||
@@ -92,6 +90,8 @@ class VNish(BMMiner, VNishFirmware):
|
|||||||
|
|
||||||
supports_shutdown = True
|
supports_shutdown = True
|
||||||
|
|
||||||
|
firmware = "VNish"
|
||||||
|
|
||||||
data_locations = VNISH_DATA_LOC
|
data_locations = VNISH_DATA_LOC
|
||||||
|
|
||||||
async def restart_backend(self) -> bool:
|
async def restart_backend(self) -> bool:
|
||||||
@@ -187,9 +187,9 @@ class VNish(BMMiner, VNishFirmware):
|
|||||||
|
|
||||||
if rpc_summary is not None:
|
if rpc_summary is not None:
|
||||||
try:
|
try:
|
||||||
return AlgoHashRate.SHA256(
|
return round(
|
||||||
rpc_summary["SUMMARY"][0]["GHS 5s"], HashUnit.SHA256.GH
|
float(float(rpc_summary["SUMMARY"][0]["GHS 5s"]) / 1000), 2
|
||||||
).into(self.algo.unit.default)
|
)
|
||||||
except (LookupError, ValueError, TypeError):
|
except (LookupError, ValueError, TypeError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -20,12 +20,7 @@ from typing import List, Optional, Protocol, Tuple, Type, TypeVar, Union
|
|||||||
|
|
||||||
from pyasic.config import MinerConfig
|
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.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.makes import MinerMake
|
|
||||||
from pyasic.errors import APIError
|
from pyasic.errors import APIError
|
||||||
from pyasic.logger import logger
|
from pyasic.logger import logger
|
||||||
from pyasic.miners.data import DataLocations, DataOptions, RPCAPICommand, WebAPICommand
|
from pyasic.miners.data import DataLocations, DataOptions, RPCAPICommand, WebAPICommand
|
||||||
@@ -41,10 +36,9 @@ class MinerProtocol(Protocol):
|
|||||||
web: _web_cls = None
|
web: _web_cls = None
|
||||||
ssh: _ssh_cls = None
|
ssh: _ssh_cls = None
|
||||||
|
|
||||||
make: MinerMake = None
|
make: str = None
|
||||||
raw_model: MinerModel = None
|
raw_model: str = None
|
||||||
firmware: MinerFirmware = None
|
firmware: str = None
|
||||||
algo = MinerAlgo.SHA256
|
|
||||||
|
|
||||||
expected_hashboards: int = 3
|
expected_hashboards: int = 3
|
||||||
expected_chips: int = None
|
expected_chips: int = None
|
||||||
@@ -85,12 +79,6 @@ class MinerProtocol(Protocol):
|
|||||||
model_data.append(f"({self.firmware})")
|
model_data.append(f"({self.firmware})")
|
||||||
return " ".join(model_data)
|
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
|
@property
|
||||||
def api(self):
|
def api(self):
|
||||||
return self.rpc
|
return self.rpc
|
||||||
@@ -195,14 +183,6 @@ class MinerProtocol(Protocol):
|
|||||||
"""
|
"""
|
||||||
return self.model
|
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]:
|
async def get_api_ver(self) -> Optional[str]:
|
||||||
"""Get the API version of the miner and is as a string.
|
"""Get the API version of the miner and is as a string.
|
||||||
|
|
||||||
@@ -269,14 +249,6 @@ class MinerProtocol(Protocol):
|
|||||||
"""
|
"""
|
||||||
return await self._get_wattage()
|
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]:
|
async def get_wattage_limit(self) -> Optional[int]:
|
||||||
"""Get wattage limit from the miner as an int.
|
"""Get wattage limit from the miner as an int.
|
||||||
|
|
||||||
@@ -365,9 +337,6 @@ class MinerProtocol(Protocol):
|
|||||||
async def _get_wattage(self) -> Optional[int]:
|
async def _get_wattage(self) -> Optional[int]:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
async def _get_voltage(self) -> Optional[float]:
|
|
||||||
pass
|
|
||||||
|
|
||||||
async def _get_wattage_limit(self) -> Optional[int]:
|
async def _get_wattage_limit(self) -> Optional[int]:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -496,14 +465,14 @@ class MinerProtocol(Protocol):
|
|||||||
"""
|
"""
|
||||||
data = MinerData(
|
data = MinerData(
|
||||||
ip=str(self.ip),
|
ip=str(self.ip),
|
||||||
device_info=self.device_info,
|
make=self.make,
|
||||||
|
model=self.model,
|
||||||
expected_chips=(
|
expected_chips=(
|
||||||
self.expected_chips * self.expected_hashboards
|
self.expected_chips * self.expected_hashboards
|
||||||
if self.expected_chips is not None
|
if self.expected_chips is not None
|
||||||
else 0
|
else 0
|
||||||
),
|
),
|
||||||
expected_hashboards=self.expected_hashboards,
|
expected_hashboards=self.expected_hashboards,
|
||||||
expected_fans=self.expected_fans,
|
|
||||||
hashboards=[
|
hashboards=[
|
||||||
HashBoard(slot=i, expected_chips=self.expected_chips)
|
HashBoard(slot=i, expected_chips=self.expected_chips)
|
||||||
for i in range(self.expected_hashboards)
|
for i in range(self.expected_hashboards)
|
||||||
|
|||||||
@@ -15,7 +15,8 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import ePIC
|
from pyasic.miners.backends import ePIC
|
||||||
from pyasic.miners.device.models import BlockMiner520i, BlockMiner720i
|
from pyasic.miners.models import BlockMiner520i
|
||||||
|
from pyasic.miners.models import BlockMiner720i
|
||||||
|
|
||||||
|
|
||||||
class ePICBlockMiner520i(ePIC, BlockMiner520i):
|
class ePICBlockMiner520i(ePIC, BlockMiner520i):
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ class DataOptions(Enum):
|
|||||||
IS_MINING = "is_mining"
|
IS_MINING = "is_mining"
|
||||||
UPTIME = "uptime"
|
UPTIME = "uptime"
|
||||||
CONFIG = "config"
|
CONFIG = "config"
|
||||||
VOLTAGE = "voltage"
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.value
|
return self.value
|
||||||
|
|||||||
@@ -1,46 +0,0 @@
|
|||||||
# ------------------------------------------------------------------------------
|
|
||||||
# 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
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
from pyasic.device.models import MinerModel
|
|
||||||
from pyasic.miners.device.makes import AuradineMake
|
|
||||||
|
|
||||||
|
|
||||||
class AuradineAD2500(AuradineMake):
|
|
||||||
raw_model = MinerModel.AURADINE.AD2500
|
|
||||||
|
|
||||||
expected_fans = 0
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
from pyasic.device.models import MinerModel
|
|
||||||
from pyasic.miners.device.makes import AuradineMake
|
|
||||||
|
|
||||||
|
|
||||||
class AuradineAD3500(AuradineMake):
|
|
||||||
raw_model = MinerModel.AURADINE.AD3500
|
|
||||||
|
|
||||||
expected_fans = 0
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
from pyasic.device.models import MinerModel
|
|
||||||
from pyasic.miners.device.makes import AuradineMake
|
|
||||||
|
|
||||||
|
|
||||||
class AuradineAI2500(AuradineMake):
|
|
||||||
raw_model = MinerModel.AURADINE.AI2500
|
|
||||||
|
|
||||||
expected_fans = 0
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
from pyasic.device.models import MinerModel
|
|
||||||
from pyasic.miners.device.makes import AuradineMake
|
|
||||||
|
|
||||||
|
|
||||||
class AuradineAI3680(AuradineMake):
|
|
||||||
raw_model = MinerModel.AURADINE.AI3680
|
|
||||||
|
|
||||||
expected_fans = 0
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
from pyasic.device.models import MinerModel
|
|
||||||
from pyasic.miners.device.makes import AuradineMake
|
|
||||||
|
|
||||||
|
|
||||||
class AuradineAT1500(AuradineMake):
|
|
||||||
raw_model = MinerModel.AURADINE.AT1500
|
|
||||||
|
|
||||||
expected_chips = 132
|
|
||||||
expected_fans = 4
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
from pyasic.device.models import MinerModel
|
|
||||||
from pyasic.miners.device.makes import AuradineMake
|
|
||||||
|
|
||||||
|
|
||||||
class AuradineAT2860(AuradineMake):
|
|
||||||
raw_model = MinerModel.AURADINE.AT2860
|
|
||||||
|
|
||||||
expected_fans = 4
|
|
||||||
|
|
||||||
|
|
||||||
class AuradineAT2880(AuradineMake):
|
|
||||||
raw_model = MinerModel.AURADINE.AT2880
|
|
||||||
|
|
||||||
expected_fans = 4
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user