Merge branch 'UpstreamData:master' into master
This commit is contained in:
@@ -47,8 +47,8 @@ def backend_str(backend: MinerTypes) -> str:
|
|||||||
return "Stock Firmware Goldshells"
|
return "Stock Firmware Goldshells"
|
||||||
case MinerTypes.LUX_OS:
|
case MinerTypes.LUX_OS:
|
||||||
return "LuxOS Firmware Miners"
|
return "LuxOS Firmware Miners"
|
||||||
case MinerTypes.EPIC:
|
case MinerTypes.MARATHON:
|
||||||
return "ePIC Firmware Miners"
|
return "Mara Firmware Miners"
|
||||||
|
|
||||||
|
|
||||||
def create_url_str(mtype: str):
|
def create_url_str(mtype: str):
|
||||||
|
|||||||
@@ -608,7 +608,7 @@ details {
|
|||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
<details>
|
<details>
|
||||||
<summary>None:</summary>
|
<summary>Mara Firmware Miners:</summary>
|
||||||
<ul>
|
<ul>
|
||||||
<details>
|
<details>
|
||||||
<summary>X19 Series:</summary>
|
<summary>X19 Series:</summary>
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
jinja2<3.1.3
|
jinja2<3.1.4
|
||||||
mkdocs
|
mkdocs
|
||||||
mkdocstrings[python]
|
mkdocstrings[python]
|
||||||
|
|||||||
@@ -25,8 +25,9 @@ from pyasic.misc import merge_dicts
|
|||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
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)
|
||||||
@@ -110,7 +111,7 @@ class MinerConfig:
|
|||||||
}
|
}
|
||||||
|
|
||||||
def as_boser(self, user_suffix: str = None) -> dict:
|
def as_boser(self, user_suffix: str = None) -> dict:
|
||||||
""""Generates the configuration in the format suitable for BOSer."""
|
""" "Generates the configuration in the format suitable for BOSer."""
|
||||||
return {
|
return {
|
||||||
**self.fan_mode.as_boser(),
|
**self.fan_mode.as_boser(),
|
||||||
**self.temperature.as_boser(),
|
**self.temperature.as_boser(),
|
||||||
@@ -138,6 +139,15 @@ 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."""
|
||||||
@@ -228,3 +238,11 @@ 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,6 +57,9 @@ 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)
|
||||||
|
|
||||||
@@ -106,3 +109,6 @@ class MinerConfigValue:
|
|||||||
|
|
||||||
def as_auradine(self) -> dict:
|
def as_auradine(self) -> dict:
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
def as_mara(self) -> dict:
|
||||||
|
return {}
|
||||||
|
|||||||
@@ -71,6 +71,15 @@ 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):
|
||||||
@@ -120,6 +129,15 @@ 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):
|
||||||
@@ -140,6 +158,9 @@ 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
|
||||||
@@ -255,4 +276,18 @@ 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:
|
||||||
return cls.default()
|
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()
|
||||||
|
|||||||
@@ -56,6 +56,13 @@ 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):
|
||||||
@@ -82,6 +89,13 @@ 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):
|
||||||
@@ -219,6 +233,17 @@ 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):
|
||||||
@@ -269,6 +294,17 @@ class MiningModeHashrateTune(MinerConfigValue):
|
|||||||
def as_epic(self) -> dict:
|
def as_epic(self) -> dict:
|
||||||
return {"ptune": {"algo": self.algo.as_epic(), "target": self.hashrate}}
|
return {"ptune": {"algo": self.algo.as_epic(), "target": self.hashrate}}
|
||||||
|
|
||||||
|
def as_mara(self) -> dict:
|
||||||
|
return {
|
||||||
|
"mode": {
|
||||||
|
"work-mode-selector": "Auto",
|
||||||
|
"concorde": {
|
||||||
|
"mode-select": "Hashrate",
|
||||||
|
"hash-target": self.hashrate,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class ManualBoardSettings(MinerConfigValue):
|
class ManualBoardSettings(MinerConfigValue):
|
||||||
@@ -320,6 +356,17 @@ 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
|
||||||
@@ -468,3 +515,28 @@ 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,6 +118,15 @@ 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(
|
||||||
@@ -177,6 +186,14 @@ 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):
|
||||||
@@ -264,9 +281,12 @@ 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) -> dict:
|
def as_epic(self, user_suffix: str = None) -> list:
|
||||||
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 = {}
|
||||||
@@ -336,6 +356,10 @@ 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):
|
||||||
@@ -427,6 +451,11 @@ 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:
|
||||||
@@ -481,3 +510,7 @@ 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,6 +38,8 @@ 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:
|
||||||
@@ -69,6 +71,7 @@ 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":
|
||||||
|
|||||||
@@ -176,11 +176,14 @@ class BOSMiner(BaseMiner):
|
|||||||
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(
|
||||||
@@ -201,9 +204,7 @@ class BOSMiner(BaseMiner):
|
|||||||
|
|
||||||
async with conn:
|
async with conn:
|
||||||
await conn.run("/etc/init.d/bosminer stop")
|
await conn.run("/etc/init.d/bosminer stop")
|
||||||
async with conn.start_sftp_client() as sftp:
|
await conn.run("echo '" + toml_conf + "' > /etc/bosminer.toml")
|
||||||
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:
|
||||||
@@ -642,6 +643,8 @@ class BOSer(BaseMiner):
|
|||||||
_web_cls = BOSerWebAPI
|
_web_cls = BOSerWebAPI
|
||||||
web: BOSerWebAPI
|
web: BOSerWebAPI
|
||||||
|
|
||||||
|
firmware = "BOS+"
|
||||||
|
|
||||||
data_locations = BOSER_DATA_LOC
|
data_locations = BOSER_DATA_LOC
|
||||||
|
|
||||||
supports_autotuning = True
|
supports_autotuning = True
|
||||||
|
|||||||
@@ -1,71 +1,69 @@
|
|||||||
from typing import Optional
|
from typing import List, Optional
|
||||||
|
|
||||||
|
from pyasic import MinerConfig
|
||||||
|
from pyasic.config import MiningModeConfig
|
||||||
|
from pyasic.data import Fan, HashBoard
|
||||||
from pyasic.errors import APIError
|
from pyasic.errors import APIError
|
||||||
from pyasic.miners.backends import AntminerModern
|
from pyasic.miners.base import BaseMiner
|
||||||
from pyasic.miners.data import (
|
from pyasic.miners.data import DataFunction, DataLocations, DataOptions, WebAPICommand
|
||||||
DataFunction,
|
from pyasic.misc import merge_dicts
|
||||||
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_get_system_info", "get_system_info")],
|
[WebAPICommand("web_overview", "overview")],
|
||||||
),
|
|
||||||
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",
|
||||||
[RPCAPICommand("rpc_version", "version")],
|
[WebAPICommand("web_overview", "overview")],
|
||||||
),
|
),
|
||||||
str(DataOptions.HOSTNAME): DataFunction(
|
str(DataOptions.HOSTNAME): DataFunction(
|
||||||
"_get_hostname",
|
"_get_hostname",
|
||||||
[WebAPICommand("web_get_system_info", "get_system_info")],
|
[WebAPICommand("web_network_config", "network_config")],
|
||||||
),
|
),
|
||||||
str(DataOptions.HASHRATE): DataFunction(
|
str(DataOptions.HASHRATE): DataFunction(
|
||||||
"_get_hashrate",
|
"_get_hashrate",
|
||||||
[RPCAPICommand("rpc_summary", "summary")],
|
[WebAPICommand("web_brief", "brief")],
|
||||||
),
|
),
|
||||||
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
|
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
|
||||||
"_get_expected_hashrate",
|
"_get_expected_hashrate",
|
||||||
[RPCAPICommand("rpc_stats", "stats")],
|
[WebAPICommand("web_brief", "brief")],
|
||||||
),
|
),
|
||||||
str(DataOptions.FANS): DataFunction(
|
str(DataOptions.HASHBOARDS): DataFunction(
|
||||||
"_get_fans",
|
"_get_hashboards",
|
||||||
[RPCAPICommand("rpc_stats", "stats")],
|
[WebAPICommand("web_hashboards", "hashboards")],
|
||||||
),
|
|
||||||
str(DataOptions.ERRORS): DataFunction(
|
|
||||||
"_get_errors",
|
|
||||||
[WebAPICommand("web_summary", "summary")],
|
|
||||||
),
|
|
||||||
str(DataOptions.FAULT_LIGHT): DataFunction(
|
|
||||||
"_get_fault_light",
|
|
||||||
[WebAPICommand("web_get_blink_status", "get_blink_status")],
|
|
||||||
),
|
|
||||||
str(DataOptions.IS_MINING): DataFunction(
|
|
||||||
"_is_mining",
|
|
||||||
[WebAPICommand("web_get_conf", "get_miner_conf")],
|
|
||||||
),
|
|
||||||
str(DataOptions.UPTIME): DataFunction(
|
|
||||||
"_get_uptime",
|
|
||||||
[RPCAPICommand("rpc_stats", "stats")],
|
|
||||||
),
|
),
|
||||||
str(DataOptions.WATTAGE): DataFunction(
|
str(DataOptions.WATTAGE): DataFunction(
|
||||||
"_get_wattage",
|
"_get_wattage",
|
||||||
[WebAPICommand("web_brief", "brief")],
|
[WebAPICommand("web_brief", "brief")],
|
||||||
),
|
),
|
||||||
|
str(DataOptions.WATTAGE_LIMIT): DataFunction(
|
||||||
|
"_get_wattage_limit",
|
||||||
|
[WebAPICommand("web_miner_config", "miner_config")],
|
||||||
|
),
|
||||||
|
str(DataOptions.FANS): DataFunction(
|
||||||
|
"_get_fans",
|
||||||
|
[WebAPICommand("web_fans", "fans")],
|
||||||
|
),
|
||||||
|
str(DataOptions.FAULT_LIGHT): DataFunction(
|
||||||
|
"_get_fault_light",
|
||||||
|
[WebAPICommand("web_locate_miner", "locate_miner")],
|
||||||
|
),
|
||||||
|
str(DataOptions.IS_MINING): DataFunction(
|
||||||
|
"_is_mining",
|
||||||
|
[WebAPICommand("web_brief", "brief")],
|
||||||
|
),
|
||||||
|
str(DataOptions.UPTIME): DataFunction(
|
||||||
|
"_get_uptime",
|
||||||
|
[WebAPICommand("web_brief", "brief")],
|
||||||
|
),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class MaraMiner(AntminerModern):
|
class MaraMiner(BaseMiner):
|
||||||
_web_cls = MaraWebAPI
|
_web_cls = MaraWebAPI
|
||||||
web: MaraWebAPI
|
web: MaraWebAPI
|
||||||
|
|
||||||
@@ -73,6 +71,52 @@ class MaraMiner(AntminerModern):
|
|||||||
|
|
||||||
firmware = "MaraFW"
|
firmware = "MaraFW"
|
||||||
|
|
||||||
|
async def fault_light_off(self) -> bool:
|
||||||
|
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:
|
||||||
try:
|
try:
|
||||||
@@ -82,6 +126,173 @@ class MaraMiner(AntminerModern):
|
|||||||
|
|
||||||
if web_brief is not None:
|
if web_brief is not None:
|
||||||
try:
|
try:
|
||||||
return web_brief["power_consumption_estimated"]
|
return round(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 = round(hb["hashrate_average"] / 1000, 2)
|
||||||
|
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 round(web_brief["hashrate_realtime"], 2)
|
||||||
|
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 round(web_brief["hashrate_ideal"] / 1000, 2)
|
||||||
|
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
|
||||||
|
|||||||
@@ -364,6 +364,7 @@ MINER_CLASSES = {
|
|||||||
"ANTMINER S19J PRO PLUS": BOSMinerS19jProPlus,
|
"ANTMINER S19J PRO PLUS": BOSMinerS19jProPlus,
|
||||||
"ANTMINER S19J PRO PLUS NOPIC": BOSMinerS19jProPlusNoPIC,
|
"ANTMINER S19J PRO PLUS NOPIC": BOSMinerS19jProPlusNoPIC,
|
||||||
"ANTMINER S19K PRO NOPIC": BOSMinerS19kProNoPIC,
|
"ANTMINER S19K PRO NOPIC": BOSMinerS19kProNoPIC,
|
||||||
|
"ANTMINER S19K PRO": BOSMinerS19kProNoPIC,
|
||||||
"ANTMINER S19 XP": BOSMinerS19XP,
|
"ANTMINER S19 XP": BOSMinerS19XP,
|
||||||
"ANTMINER T19": BOSMinerT19,
|
"ANTMINER T19": BOSMinerT19,
|
||||||
"ANTMINER S21": BOSMinerS21,
|
"ANTMINER S21": BOSMinerS21,
|
||||||
@@ -553,7 +554,14 @@ class MinerFactory:
|
|||||||
and self._parse_web_type(x[0], x[1]) is not None,
|
and self._parse_web_type(x[0], x[1]) is not None,
|
||||||
)
|
)
|
||||||
if text is not None:
|
if text is not None:
|
||||||
return self._parse_web_type(text, resp)
|
mtype = self._parse_web_type(text, resp)
|
||||||
|
if mtype == MinerTypes.ANTMINER:
|
||||||
|
# could still be mara
|
||||||
|
auth = httpx.DigestAuth("root", "root")
|
||||||
|
res = await self.send_web_command(ip, "/kaonsu/v1/brief", auth=auth)
|
||||||
|
if res is not None:
|
||||||
|
mtype = MinerTypes.MARATHON
|
||||||
|
return mtype
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def _web_ping(
|
async def _web_ping(
|
||||||
|
|||||||
@@ -21,22 +21,33 @@ class MinerListenerProtocol(asyncio.Protocol):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.responses = {}
|
self.responses = {}
|
||||||
self.transport = None
|
self.transport = None
|
||||||
|
self.new_miner = None
|
||||||
|
|
||||||
|
async def get_new_miner(self):
|
||||||
|
try:
|
||||||
|
while self.new_miner is None:
|
||||||
|
await asyncio.sleep(0)
|
||||||
|
return self.new_miner
|
||||||
|
finally:
|
||||||
|
self.new_miner = None
|
||||||
|
|
||||||
def connection_made(self, transport):
|
def connection_made(self, transport):
|
||||||
self.transport = transport
|
self.transport = transport
|
||||||
|
|
||||||
@staticmethod
|
def datagram_received(self, data, _addr):
|
||||||
def datagram_received(data, _addr):
|
if data == b"OK\x00\x00\x00\x00\x00\x00\x00\x00":
|
||||||
|
return
|
||||||
m = data.decode()
|
m = data.decode()
|
||||||
if "," in m:
|
if "," in m:
|
||||||
ip, mac = m.split(",")
|
ip, mac = m.split(",")
|
||||||
|
if "/" in ip:
|
||||||
|
ip = ip.replace("[", "").split("/")[0]
|
||||||
else:
|
else:
|
||||||
d = m[:-1].split("MAC")
|
d = m[:-1].split("MAC")
|
||||||
ip = d[0][3:]
|
ip = d[0][3:]
|
||||||
mac = d[1][1:]
|
mac = d[1][1:]
|
||||||
|
|
||||||
new_miner = {"IP": ip, "MAC": mac.upper()}
|
self.new_miner = {"IP": ip, "MAC": mac.upper()}
|
||||||
MinerListener().new_miner = new_miner
|
|
||||||
|
|
||||||
def connection_lost(self, _):
|
def connection_lost(self, _):
|
||||||
pass
|
pass
|
||||||
@@ -45,32 +56,32 @@ class MinerListenerProtocol(asyncio.Protocol):
|
|||||||
class MinerListener:
|
class MinerListener:
|
||||||
def __init__(self, bind_addr: str = "0.0.0.0"):
|
def __init__(self, bind_addr: str = "0.0.0.0"):
|
||||||
self.found_miners = []
|
self.found_miners = []
|
||||||
self.new_miner = None
|
self.stop = asyncio.Event()
|
||||||
self.stop = False
|
|
||||||
self.bind_addr = bind_addr
|
self.bind_addr = bind_addr
|
||||||
|
|
||||||
async def listen(self):
|
async def listen(self):
|
||||||
self.stop = False
|
|
||||||
|
|
||||||
loop = asyncio.get_running_loop()
|
loop = asyncio.get_running_loop()
|
||||||
|
|
||||||
transport_14235, _ = await loop.create_datagram_endpoint(
|
transport_14235, protocol_14235 = await loop.create_datagram_endpoint(
|
||||||
MinerListenerProtocol, local_addr=(self.bind_addr, 14235)
|
MinerListenerProtocol, local_addr=(self.bind_addr, 14235)
|
||||||
)
|
)
|
||||||
transport_8888, _ = await loop.create_datagram_endpoint(
|
transport_8888, protocol_8888 = await loop.create_datagram_endpoint(
|
||||||
MinerListenerProtocol, local_addr=(self.bind_addr, 8888)
|
MinerListenerProtocol, local_addr=(self.bind_addr, 8888)
|
||||||
)
|
)
|
||||||
|
try:
|
||||||
|
while not self.stop.is_set():
|
||||||
|
tasks = [
|
||||||
|
asyncio.create_task(protocol_14235.get_new_miner()),
|
||||||
|
asyncio.create_task(protocol_8888.get_new_miner()),
|
||||||
|
]
|
||||||
|
await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)
|
||||||
|
for t in tasks:
|
||||||
|
if t.done():
|
||||||
|
yield t.result()
|
||||||
|
|
||||||
while True:
|
finally:
|
||||||
if self.new_miner:
|
transport_14235.close()
|
||||||
yield self.new_miner
|
transport_8888.close()
|
||||||
self.found_miners.append(self.new_miner)
|
|
||||||
self.new_miner = None
|
|
||||||
if self.stop:
|
|
||||||
transport_14235.close()
|
|
||||||
transport_8888.close()
|
|
||||||
break
|
|
||||||
await asyncio.sleep(0)
|
|
||||||
|
|
||||||
async def cancel(self):
|
async def cancel(self):
|
||||||
self.stop = True
|
self.stop = True
|
||||||
|
|||||||
@@ -32,6 +32,10 @@ class MinerNetwork:
|
|||||||
|
|
||||||
def __init__(self, hosts: List[ipaddress.IPv4Address]):
|
def __init__(self, hosts: List[ipaddress.IPv4Address]):
|
||||||
self.hosts = hosts
|
self.hosts = hosts
|
||||||
|
semaphore_limit = settings.get("network_scan_semaphore", 255)
|
||||||
|
if semaphore_limit is None:
|
||||||
|
semaphore_limit = 255
|
||||||
|
self.semaphore = asyncio.Semaphore(semaphore_limit)
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
return len(self.hosts)
|
return len(self.hosts)
|
||||||
@@ -153,8 +157,16 @@ class MinerNetwork:
|
|||||||
except TimeoutError:
|
except TimeoutError:
|
||||||
yield None
|
yield None
|
||||||
|
|
||||||
|
async def ping_and_get_miner(
|
||||||
|
self, ip: ipaddress.ip_address
|
||||||
|
) -> Union[None, AnyMiner]:
|
||||||
|
if settings.get("network_scan_semaphore") is None:
|
||||||
|
return await self._ping_and_get_miner(ip)
|
||||||
|
async with self.semaphore:
|
||||||
|
return await self._ping_and_get_miner(ip)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def ping_and_get_miner(ip: ipaddress.ip_address) -> Union[None, AnyMiner]:
|
async def _ping_and_get_miner(ip: ipaddress.ip_address) -> Union[None, AnyMiner]:
|
||||||
try:
|
try:
|
||||||
return await ping_and_get_miner(ip)
|
return await ping_and_get_miner(ip)
|
||||||
except ConnectionRefusedError:
|
except ConnectionRefusedError:
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ from httpx import AsyncHTTPTransport
|
|||||||
_settings = { # defaults
|
_settings = { # defaults
|
||||||
"network_ping_retries": 1,
|
"network_ping_retries": 1,
|
||||||
"network_ping_timeout": 3,
|
"network_ping_timeout": 3,
|
||||||
|
"network_scan_semaphore": None,
|
||||||
"factory_get_retries": 1,
|
"factory_get_retries": 1,
|
||||||
"factory_get_timeout": 3,
|
"factory_get_timeout": 3,
|
||||||
"get_data_retries": 1,
|
"get_data_retries": 1,
|
||||||
@@ -46,9 +47,10 @@ _settings = { # defaults
|
|||||||
|
|
||||||
ssl_cxt = httpx.create_ssl_context()
|
ssl_cxt = httpx.create_ssl_context()
|
||||||
|
|
||||||
#this function configures socket options like SO_LINGER and returns an AsyncHTTPTransport instance to perform asynchronous HTTP requests
|
|
||||||
#using those options.
|
# this function configures socket options like SO_LINGER and returns an AsyncHTTPTransport instance to perform asynchronous HTTP requests
|
||||||
#SO_LINGER controls what happens when you close a socket with unsent data - it allows specifying linger time for the data to be sent.
|
# using those options.
|
||||||
|
# SO_LINGER controls what happens when you close a socket with unsent data - it allows specifying linger time for the data to be sent.
|
||||||
def transport(verify: Union[str, bool, SSLContext] = ssl_cxt):
|
def transport(verify: Union[str, bool, SSLContext] = ssl_cxt):
|
||||||
l_onoff = 1
|
l_onoff = 1
|
||||||
l_linger = get("so_linger_time", 1000)
|
l_linger = get("so_linger_time", 1000)
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ class AntminerModernSSH(BaseSSH):
|
|||||||
Args:
|
Args:
|
||||||
ip (str): The IP address of the Antminer device.
|
ip (str): The IP address of the Antminer device.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, ip: str):
|
def __init__(self, ip: str):
|
||||||
super().__init__(ip)
|
super().__init__(ip)
|
||||||
self.pwd = settings.get("default_antminer_ssh_password", "root")
|
self.pwd = settings.get("default_antminer_ssh_password", "root")
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ from pyasic.web.base import BaseWebAPI
|
|||||||
class AntminerModernWebAPI(BaseWebAPI):
|
class AntminerModernWebAPI(BaseWebAPI):
|
||||||
def __init__(self, ip: str) -> None:
|
def __init__(self, ip: str) -> None:
|
||||||
"""Initialize the modern Antminer API client with a specific IP address.
|
"""Initialize the modern Antminer API client with a specific IP address.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
ip (str): IP address of the Antminer device.
|
ip (str): IP address of the Antminer device.
|
||||||
"""
|
"""
|
||||||
@@ -45,14 +45,14 @@ class AntminerModernWebAPI(BaseWebAPI):
|
|||||||
**parameters: Any,
|
**parameters: Any,
|
||||||
) -> dict:
|
) -> dict:
|
||||||
"""Send a command to the Antminer device using HTTP digest authentication.
|
"""Send a command to the Antminer device using HTTP digest authentication.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
command (str | bytes): The CGI command to send.
|
command (str | bytes): The CGI command to send.
|
||||||
ignore_errors (bool): If True, ignore any HTTP errors.
|
ignore_errors (bool): If True, ignore any HTTP errors.
|
||||||
allow_warning (bool): If True, proceed with warnings.
|
allow_warning (bool): If True, proceed with warnings.
|
||||||
privileged (bool): If set to True, requires elevated privileges.
|
privileged (bool): If set to True, requires elevated privileges.
|
||||||
**parameters: Arbitrary keyword arguments to be sent as parameters in the request.
|
**parameters: Arbitrary keyword arguments to be sent as parameters in the request.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: The JSON response from the device or an empty dictionary if an error occurs.
|
dict: The JSON response from the device or an empty dictionary if an error occurs.
|
||||||
"""
|
"""
|
||||||
@@ -84,12 +84,12 @@ class AntminerModernWebAPI(BaseWebAPI):
|
|||||||
self, *commands: str, ignore_errors: bool = False, allow_warning: bool = True
|
self, *commands: str, ignore_errors: bool = False, allow_warning: bool = True
|
||||||
) -> dict:
|
) -> dict:
|
||||||
"""Execute multiple commands simultaneously.
|
"""Execute multiple commands simultaneously.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
*commands (str): Multiple command strings to be executed.
|
*commands (str): Multiple command strings to be executed.
|
||||||
ignore_errors (bool): If True, ignore any HTTP errors.
|
ignore_errors (bool): If True, ignore any HTTP errors.
|
||||||
allow_warning (bool): If True, proceed with warnings.
|
allow_warning (bool): If True, proceed with warnings.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary containing the results of all commands executed.
|
dict: A dictionary containing the results of all commands executed.
|
||||||
"""
|
"""
|
||||||
@@ -111,11 +111,11 @@ class AntminerModernWebAPI(BaseWebAPI):
|
|||||||
self, client: httpx.AsyncClient, command: str
|
self, client: httpx.AsyncClient, command: str
|
||||||
) -> dict:
|
) -> dict:
|
||||||
"""Helper function for handling individual commands in a multicommand execution.
|
"""Helper function for handling individual commands in a multicommand execution.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
client (httpx.AsyncClient): The HTTP client to use for the request.
|
client (httpx.AsyncClient): The HTTP client to use for the request.
|
||||||
command (str): The command to be executed.
|
command (str): The command to be executed.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary containing the response of the executed command.
|
dict: A dictionary containing the response of the executed command.
|
||||||
"""
|
"""
|
||||||
@@ -137,7 +137,7 @@ class AntminerModernWebAPI(BaseWebAPI):
|
|||||||
|
|
||||||
async def get_miner_conf(self) -> dict:
|
async def get_miner_conf(self) -> dict:
|
||||||
"""Retrieve the miner configuration from the Antminer device.
|
"""Retrieve the miner configuration from the Antminer device.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary containing the current configuration of the miner.
|
dict: A dictionary containing the current configuration of the miner.
|
||||||
"""
|
"""
|
||||||
@@ -145,10 +145,10 @@ class AntminerModernWebAPI(BaseWebAPI):
|
|||||||
|
|
||||||
async def set_miner_conf(self, conf: dict) -> dict:
|
async def set_miner_conf(self, conf: dict) -> dict:
|
||||||
"""Set the configuration for the miner.
|
"""Set the configuration for the miner.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
conf (dict): A dictionary of configuration settings to apply to the miner.
|
conf (dict): A dictionary of configuration settings to apply to the miner.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary response from the device after setting the configuration.
|
dict: A dictionary response from the device after setting the configuration.
|
||||||
"""
|
"""
|
||||||
@@ -156,10 +156,10 @@ class AntminerModernWebAPI(BaseWebAPI):
|
|||||||
|
|
||||||
async def blink(self, blink: bool) -> dict:
|
async def blink(self, blink: bool) -> dict:
|
||||||
"""Control the blinking of the LED on the miner device.
|
"""Control the blinking of the LED on the miner device.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
blink (bool): True to start blinking, False to stop.
|
blink (bool): True to start blinking, False to stop.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary response from the device after the command execution.
|
dict: A dictionary response from the device after the command execution.
|
||||||
"""
|
"""
|
||||||
@@ -169,7 +169,7 @@ class AntminerModernWebAPI(BaseWebAPI):
|
|||||||
|
|
||||||
async def reboot(self) -> dict:
|
async def reboot(self) -> dict:
|
||||||
"""Reboot the miner device.
|
"""Reboot the miner device.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary response from the device confirming the reboot command.
|
dict: A dictionary response from the device confirming the reboot command.
|
||||||
"""
|
"""
|
||||||
@@ -177,7 +177,7 @@ class AntminerModernWebAPI(BaseWebAPI):
|
|||||||
|
|
||||||
async def get_system_info(self) -> dict:
|
async def get_system_info(self) -> dict:
|
||||||
"""Retrieve system information from the miner.
|
"""Retrieve system information from the miner.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary containing system information of the miner.
|
dict: A dictionary containing system information of the miner.
|
||||||
"""
|
"""
|
||||||
@@ -185,7 +185,7 @@ class AntminerModernWebAPI(BaseWebAPI):
|
|||||||
|
|
||||||
async def get_network_info(self) -> dict:
|
async def get_network_info(self) -> dict:
|
||||||
"""Retrieve network configuration information from the miner.
|
"""Retrieve network configuration information from the miner.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary containing the network configuration of the miner.
|
dict: A dictionary containing the network configuration of the miner.
|
||||||
"""
|
"""
|
||||||
@@ -193,7 +193,7 @@ class AntminerModernWebAPI(BaseWebAPI):
|
|||||||
|
|
||||||
async def summary(self) -> dict:
|
async def summary(self) -> dict:
|
||||||
"""Get a summary of the miner's status and performance.
|
"""Get a summary of the miner's status and performance.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A summary of the miner's current operational status.
|
dict: A summary of the miner's current operational status.
|
||||||
"""
|
"""
|
||||||
@@ -201,7 +201,7 @@ class AntminerModernWebAPI(BaseWebAPI):
|
|||||||
|
|
||||||
async def get_blink_status(self) -> dict:
|
async def get_blink_status(self) -> dict:
|
||||||
"""Check the status of the LED blinking on the miner.
|
"""Check the status of the LED blinking on the miner.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary indicating whether the LED is currently blinking.
|
dict: A dictionary indicating whether the LED is currently blinking.
|
||||||
"""
|
"""
|
||||||
@@ -217,7 +217,7 @@ class AntminerModernWebAPI(BaseWebAPI):
|
|||||||
protocol: int,
|
protocol: int,
|
||||||
) -> dict:
|
) -> dict:
|
||||||
"""Set the network configuration of the miner.
|
"""Set the network configuration of the miner.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
ip (str): IP address of the device.
|
ip (str): IP address of the device.
|
||||||
dns (str): DNS server IP address.
|
dns (str): DNS server IP address.
|
||||||
@@ -225,7 +225,7 @@ class AntminerModernWebAPI(BaseWebAPI):
|
|||||||
subnet_mask (str): Network subnet mask.
|
subnet_mask (str): Network subnet mask.
|
||||||
hostname (str): Hostname of the device.
|
hostname (str): Hostname of the device.
|
||||||
protocol (int): Network protocol used.
|
protocol (int): Network protocol used.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary response from the device after setting the network configuration.
|
dict: A dictionary response from the device after setting the network configuration.
|
||||||
"""
|
"""
|
||||||
@@ -243,7 +243,7 @@ class AntminerModernWebAPI(BaseWebAPI):
|
|||||||
class AntminerOldWebAPI(BaseWebAPI):
|
class AntminerOldWebAPI(BaseWebAPI):
|
||||||
def __init__(self, ip: str) -> None:
|
def __init__(self, ip: str) -> None:
|
||||||
"""Initialize the old Antminer API client with a specific IP address.
|
"""Initialize the old Antminer API client with a specific IP address.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
ip (str): IP address of the Antminer device.
|
ip (str): IP address of the Antminer device.
|
||||||
"""
|
"""
|
||||||
@@ -260,14 +260,14 @@ class AntminerOldWebAPI(BaseWebAPI):
|
|||||||
**parameters: Any,
|
**parameters: Any,
|
||||||
) -> dict:
|
) -> dict:
|
||||||
"""Send a command to the Antminer device using HTTP digest authentication.
|
"""Send a command to the Antminer device using HTTP digest authentication.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
command (str | bytes): The CGI command to send.
|
command (str | bytes): The CGI command to send.
|
||||||
ignore_errors (bool): If True, ignore any HTTP errors.
|
ignore_errors (bool): If True, ignore any HTTP errors.
|
||||||
allow_warning (bool): If True, proceed with warnings.
|
allow_warning (bool): If True, proceed with warnings.
|
||||||
privileged (bool): If set to True, requires elevated privileges.
|
privileged (bool): If set to True, requires elevated privileges.
|
||||||
**parameters: Arbitrary keyword arguments to be sent as parameters in the request.
|
**parameters: Arbitrary keyword arguments to be sent as parameters in the request.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: The JSON response from the device or an empty dictionary if an error occurs.
|
dict: The JSON response from the device or an empty dictionary if an error occurs.
|
||||||
"""
|
"""
|
||||||
@@ -297,12 +297,12 @@ class AntminerOldWebAPI(BaseWebAPI):
|
|||||||
self, *commands: str, ignore_errors: bool = False, allow_warning: bool = True
|
self, *commands: str, ignore_errors: bool = False, allow_warning: bool = True
|
||||||
) -> dict:
|
) -> dict:
|
||||||
"""Execute multiple commands simultaneously.
|
"""Execute multiple commands simultaneously.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
*commands (str): Multiple command strings to be executed.
|
*commands (str): Multiple command strings to be executed.
|
||||||
ignore_errors (bool): If True, ignore any HTTP errors.
|
ignore_errors (bool): If True, ignore any HTTP errors.
|
||||||
allow_warning (bool): If True, proceed with warnings.
|
allow_warning (bool): If True, proceed with warnings.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary containing the results of all commands executed.
|
dict: A dictionary containing the results of all commands executed.
|
||||||
"""
|
"""
|
||||||
@@ -326,7 +326,7 @@ class AntminerOldWebAPI(BaseWebAPI):
|
|||||||
|
|
||||||
async def get_system_info(self) -> dict:
|
async def get_system_info(self) -> dict:
|
||||||
"""Retrieve system information from the miner.
|
"""Retrieve system information from the miner.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary containing system information of the miner.
|
dict: A dictionary containing system information of the miner.
|
||||||
"""
|
"""
|
||||||
@@ -334,10 +334,10 @@ class AntminerOldWebAPI(BaseWebAPI):
|
|||||||
|
|
||||||
async def blink(self, blink: bool) -> dict:
|
async def blink(self, blink: bool) -> dict:
|
||||||
"""Control the blinking of the LED on the miner device.
|
"""Control the blinking of the LED on the miner device.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
blink (bool): True to start blinking, False to stop.
|
blink (bool): True to start blinking, False to stop.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary response from the device after the command execution.
|
dict: A dictionary response from the device after the command execution.
|
||||||
"""
|
"""
|
||||||
@@ -347,7 +347,7 @@ class AntminerOldWebAPI(BaseWebAPI):
|
|||||||
|
|
||||||
async def reboot(self) -> dict:
|
async def reboot(self) -> dict:
|
||||||
"""Reboot the miner device.
|
"""Reboot the miner device.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary response from the device confirming the reboot command.
|
dict: A dictionary response from the device confirming the reboot command.
|
||||||
"""
|
"""
|
||||||
@@ -355,7 +355,7 @@ class AntminerOldWebAPI(BaseWebAPI):
|
|||||||
|
|
||||||
async def get_blink_status(self) -> dict:
|
async def get_blink_status(self) -> dict:
|
||||||
"""Check the status of the LED blinking on the miner.
|
"""Check the status of the LED blinking on the miner.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary indicating whether the LED is currently blinking.
|
dict: A dictionary indicating whether the LED is currently blinking.
|
||||||
"""
|
"""
|
||||||
@@ -363,7 +363,7 @@ class AntminerOldWebAPI(BaseWebAPI):
|
|||||||
|
|
||||||
async def get_miner_conf(self) -> dict:
|
async def get_miner_conf(self) -> dict:
|
||||||
"""Retrieve the miner configuration from the Antminer device.
|
"""Retrieve the miner configuration from the Antminer device.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary containing the current configuration of the miner.
|
dict: A dictionary containing the current configuration of the miner.
|
||||||
"""
|
"""
|
||||||
@@ -371,10 +371,10 @@ class AntminerOldWebAPI(BaseWebAPI):
|
|||||||
|
|
||||||
async def set_miner_conf(self, conf: dict) -> dict:
|
async def set_miner_conf(self, conf: dict) -> dict:
|
||||||
"""Set the configuration for the miner.
|
"""Set the configuration for the miner.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
conf (dict): A dictionary of configuration settings to apply to the miner.
|
conf (dict): A dictionary of configuration settings to apply to the miner.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary response from the device after setting the configuration.
|
dict: A dictionary response from the device after setting the configuration.
|
||||||
"""
|
"""
|
||||||
@@ -382,7 +382,7 @@ class AntminerOldWebAPI(BaseWebAPI):
|
|||||||
|
|
||||||
async def stats(self) -> dict:
|
async def stats(self) -> dict:
|
||||||
"""Retrieve detailed statistical data of the mining operation.
|
"""Retrieve detailed statistical data of the mining operation.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: Detailed statistics of the miner's operation.
|
dict: Detailed statistics of the miner's operation.
|
||||||
"""
|
"""
|
||||||
@@ -390,7 +390,7 @@ class AntminerOldWebAPI(BaseWebAPI):
|
|||||||
|
|
||||||
async def summary(self) -> dict:
|
async def summary(self) -> dict:
|
||||||
"""Get a summary of the miner's status and performance.
|
"""Get a summary of the miner's status and performance.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A summary of the miner's current operational status.
|
dict: A summary of the miner's current operational status.
|
||||||
"""
|
"""
|
||||||
@@ -398,7 +398,7 @@ class AntminerOldWebAPI(BaseWebAPI):
|
|||||||
|
|
||||||
async def pools(self) -> dict:
|
async def pools(self) -> dict:
|
||||||
"""Retrieve current pool information associated with the miner.
|
"""Retrieve current pool information associated with the miner.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: Information about the mining pools configured in the miner.
|
dict: Information about the mining pools configured in the miner.
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ from pyasic.web.base import BaseWebAPI
|
|||||||
class AuradineWebAPI(BaseWebAPI):
|
class AuradineWebAPI(BaseWebAPI):
|
||||||
def __init__(self, ip: str) -> None:
|
def __init__(self, ip: str) -> None:
|
||||||
"""Initializes the API client for interacting with Auradine mining devices.
|
"""Initializes the API client for interacting with Auradine mining devices.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
ip (str): IP address of the Auradine miner.
|
ip (str): IP address of the Auradine miner.
|
||||||
"""
|
"""
|
||||||
@@ -43,7 +43,7 @@ class AuradineWebAPI(BaseWebAPI):
|
|||||||
|
|
||||||
async def auth(self) -> str | None:
|
async def auth(self) -> str | None:
|
||||||
"""Authenticate and retrieve a web token from the Auradine miner.
|
"""Authenticate and retrieve a web token from the Auradine miner.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
str | None: A token if authentication is successful, None otherwise.
|
str | None: A token if authentication is successful, None otherwise.
|
||||||
"""
|
"""
|
||||||
@@ -76,14 +76,14 @@ class AuradineWebAPI(BaseWebAPI):
|
|||||||
**parameters: Any,
|
**parameters: Any,
|
||||||
) -> dict:
|
) -> dict:
|
||||||
"""Send a command to the Auradine miner, handling authentication and retries.
|
"""Send a command to the Auradine miner, handling authentication and retries.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
command (str | bytes): The specific command to execute.
|
command (str | bytes): The specific command to execute.
|
||||||
ignore_errors (bool): Whether to ignore HTTP errors.
|
ignore_errors (bool): Whether to ignore HTTP errors.
|
||||||
allow_warning (bool): Whether to proceed with warnings.
|
allow_warning (bool): Whether to proceed with warnings.
|
||||||
privileged (bool): Whether the command requires privileged access.
|
privileged (bool): Whether the command requires privileged access.
|
||||||
**parameters: Additional parameters for the command.
|
**parameters: Additional parameters for the command.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: The JSON response from the device.
|
dict: The JSON response from the device.
|
||||||
"""
|
"""
|
||||||
@@ -125,12 +125,12 @@ class AuradineWebAPI(BaseWebAPI):
|
|||||||
self, *commands: str, ignore_errors: bool = False, allow_warning: bool = True
|
self, *commands: str, ignore_errors: bool = False, allow_warning: bool = True
|
||||||
) -> dict:
|
) -> dict:
|
||||||
"""Execute multiple commands simultaneously on the Auradine miner.
|
"""Execute multiple commands simultaneously on the Auradine miner.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
*commands (str): Commands to execute.
|
*commands (str): Commands to execute.
|
||||||
ignore_errors (bool): Whether to ignore errors during command execution.
|
ignore_errors (bool): Whether to ignore errors during command execution.
|
||||||
allow_warning (bool): Whether to proceed despite warnings.
|
allow_warning (bool): Whether to proceed despite warnings.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary containing responses for all commands executed.
|
dict: A dictionary containing responses for all commands executed.
|
||||||
"""
|
"""
|
||||||
@@ -157,7 +157,7 @@ class AuradineWebAPI(BaseWebAPI):
|
|||||||
|
|
||||||
async def factory_reset(self) -> dict:
|
async def factory_reset(self) -> dict:
|
||||||
"""Perform a factory reset on the Auradine miner.
|
"""Perform a factory reset on the Auradine miner.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary indicating the result of the reset operation.
|
dict: A dictionary indicating the result of the reset operation.
|
||||||
"""
|
"""
|
||||||
@@ -165,7 +165,7 @@ class AuradineWebAPI(BaseWebAPI):
|
|||||||
|
|
||||||
async def get_fan(self) -> dict:
|
async def get_fan(self) -> dict:
|
||||||
"""Retrieve the current fan status from the Auradine miner.
|
"""Retrieve the current fan status from the Auradine miner.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary containing the current fan status.
|
dict: A dictionary containing the current fan status.
|
||||||
"""
|
"""
|
||||||
@@ -173,11 +173,11 @@ class AuradineWebAPI(BaseWebAPI):
|
|||||||
|
|
||||||
async def set_fan(self, fan: int, speed_pct: int) -> dict:
|
async def set_fan(self, fan: int, speed_pct: int) -> dict:
|
||||||
"""Set the speed of a specific fan on the Auradine miner.
|
"""Set the speed of a specific fan on the Auradine miner.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
fan (int): The index of the fan to control.
|
fan (int): The index of the fan to control.
|
||||||
speed_pct (int): The speed percentage to set for the fan.
|
speed_pct (int): The speed percentage to set for the fan.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary indicating the result of the operation.
|
dict: A dictionary indicating the result of the operation.
|
||||||
"""
|
"""
|
||||||
@@ -185,11 +185,11 @@ class AuradineWebAPI(BaseWebAPI):
|
|||||||
|
|
||||||
async def firmware_upgrade(self, url: str = None, version: str = "latest") -> dict:
|
async def firmware_upgrade(self, url: str = None, version: str = "latest") -> dict:
|
||||||
"""Upgrade the firmware of the Auradine miner.
|
"""Upgrade the firmware of the Auradine miner.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
url (str, optional): The URL to download the firmware from.
|
url (str, optional): The URL to download the firmware from.
|
||||||
version (str, optional): The version of the firmware to upgrade to, defaults to 'latest'.
|
version (str, optional): The version of the firmware to upgrade to, defaults to 'latest'.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary indicating the result of the firmware upgrade.
|
dict: A dictionary indicating the result of the firmware upgrade.
|
||||||
"""
|
"""
|
||||||
@@ -199,7 +199,7 @@ class AuradineWebAPI(BaseWebAPI):
|
|||||||
|
|
||||||
async def get_frequency(self) -> dict:
|
async def get_frequency(self) -> dict:
|
||||||
"""Retrieve the current frequency settings of the Auradine miner.
|
"""Retrieve the current frequency settings of the Auradine miner.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary containing the frequency settings.
|
dict: A dictionary containing the frequency settings.
|
||||||
"""
|
"""
|
||||||
@@ -207,11 +207,11 @@ class AuradineWebAPI(BaseWebAPI):
|
|||||||
|
|
||||||
async def set_frequency(self, board: int, frequency: float) -> dict:
|
async def set_frequency(self, board: int, frequency: float) -> dict:
|
||||||
"""Set the frequency for a specific board on the Auradine miner.
|
"""Set the frequency for a specific board on the Auradine miner.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
board (int): The index of the board to configure.
|
board (int): The index of the board to configure.
|
||||||
frequency (float): The frequency in MHz to set for the board.
|
frequency (float): The frequency in MHz to set for the board.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary indicating the result of setting the frequency.
|
dict: A dictionary indicating the result of setting the frequency.
|
||||||
"""
|
"""
|
||||||
@@ -219,7 +219,7 @@ class AuradineWebAPI(BaseWebAPI):
|
|||||||
|
|
||||||
async def ipreport(self) -> dict:
|
async def ipreport(self) -> dict:
|
||||||
"""Generate an IP report for the Auradine miner.
|
"""Generate an IP report for the Auradine miner.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary containing the IP report details.
|
dict: A dictionary containing the IP report details.
|
||||||
"""
|
"""
|
||||||
@@ -227,7 +227,7 @@ class AuradineWebAPI(BaseWebAPI):
|
|||||||
|
|
||||||
async def get_led(self) -> dict:
|
async def get_led(self) -> dict:
|
||||||
"""Retrieve the current LED status from the Auradine miner.
|
"""Retrieve the current LED status from the Auradine miner.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary containing the current status of the LED settings.
|
dict: A dictionary containing the current status of the LED settings.
|
||||||
"""
|
"""
|
||||||
@@ -235,10 +235,10 @@ class AuradineWebAPI(BaseWebAPI):
|
|||||||
|
|
||||||
async def set_led(self, code: int) -> dict:
|
async def set_led(self, code: int) -> dict:
|
||||||
"""Set the LED code on the Auradine miner.
|
"""Set the LED code on the Auradine miner.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
code (int): The code that determines the LED behavior.
|
code (int): The code that determines the LED behavior.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary indicating the result of the operation.
|
dict: A dictionary indicating the result of the operation.
|
||||||
"""
|
"""
|
||||||
@@ -246,13 +246,13 @@ class AuradineWebAPI(BaseWebAPI):
|
|||||||
|
|
||||||
async def set_led_custom(self, code: int, led_1: int, led_2: int, msg: str) -> dict:
|
async def set_led_custom(self, code: int, led_1: int, led_2: int, msg: str) -> dict:
|
||||||
"""Set custom LED configurations including messages.
|
"""Set custom LED configurations including messages.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
code (int): The LED code to set.
|
code (int): The LED code to set.
|
||||||
led_1 (int): The first LED indicator number.
|
led_1 (int): The first LED indicator number.
|
||||||
led_2 (int): The second LED indicator number.
|
led_2 (int): The second LED indicator number.
|
||||||
msg (str): The message to display or represent with LEDs.
|
msg (str): The message to display or represent with LEDs.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary indicating the result of the custom LED configuration.
|
dict: A dictionary indicating the result of the custom LED configuration.
|
||||||
"""
|
"""
|
||||||
@@ -262,7 +262,7 @@ class AuradineWebAPI(BaseWebAPI):
|
|||||||
|
|
||||||
async def get_mode(self) -> dict:
|
async def get_mode(self) -> dict:
|
||||||
"""Retrieve the current operational mode of the Auradine miner.
|
"""Retrieve the current operational mode of the Auradine miner.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary containing the current mode settings.
|
dict: A dictionary containing the current mode settings.
|
||||||
"""
|
"""
|
||||||
@@ -270,10 +270,10 @@ class AuradineWebAPI(BaseWebAPI):
|
|||||||
|
|
||||||
async def set_mode(self, **kwargs) -> dict:
|
async def set_mode(self, **kwargs) -> dict:
|
||||||
"""Set the operational mode of the Auradine miner.
|
"""Set the operational mode of the Auradine miner.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
**kwargs: Mode settings specified as keyword arguments.
|
**kwargs: Mode settings specified as keyword arguments.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary indicating the result of the mode setting operation.
|
dict: A dictionary indicating the result of the mode setting operation.
|
||||||
"""
|
"""
|
||||||
@@ -281,7 +281,7 @@ class AuradineWebAPI(BaseWebAPI):
|
|||||||
|
|
||||||
async def get_network(self) -> dict:
|
async def get_network(self) -> dict:
|
||||||
"""Retrieve the network configuration settings of the Auradine miner.
|
"""Retrieve the network configuration settings of the Auradine miner.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary containing the network configuration details.
|
dict: A dictionary containing the network configuration details.
|
||||||
"""
|
"""
|
||||||
@@ -289,10 +289,10 @@ class AuradineWebAPI(BaseWebAPI):
|
|||||||
|
|
||||||
async def set_network(self, **kwargs) -> dict:
|
async def set_network(self, **kwargs) -> dict:
|
||||||
"""Set the network configuration of the Auradine miner.
|
"""Set the network configuration of the Auradine miner.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
**kwargs: Network settings specified as keyword arguments.
|
**kwargs: Network settings specified as keyword arguments.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary indicating the result of the network configuration.
|
dict: A dictionary indicating the result of the network configuration.
|
||||||
"""
|
"""
|
||||||
@@ -300,10 +300,10 @@ class AuradineWebAPI(BaseWebAPI):
|
|||||||
|
|
||||||
async def password(self, password: str) -> dict:
|
async def password(self, password: str) -> dict:
|
||||||
"""Change the password used for accessing the Auradine miner.
|
"""Change the password used for accessing the Auradine miner.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
password (str): The new password to set.
|
password (str): The new password to set.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary indicating the result of the password change operation.
|
dict: A dictionary indicating the result of the password change operation.
|
||||||
"""
|
"""
|
||||||
@@ -315,7 +315,7 @@ class AuradineWebAPI(BaseWebAPI):
|
|||||||
|
|
||||||
async def get_psu(self) -> dict:
|
async def get_psu(self) -> dict:
|
||||||
"""Retrieve the status of the power supply unit (PSU) from the Auradine miner.
|
"""Retrieve the status of the power supply unit (PSU) from the Auradine miner.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary containing the PSU status.
|
dict: A dictionary containing the PSU status.
|
||||||
"""
|
"""
|
||||||
@@ -323,10 +323,10 @@ class AuradineWebAPI(BaseWebAPI):
|
|||||||
|
|
||||||
async def set_psu(self, voltage: float) -> dict:
|
async def set_psu(self, voltage: float) -> dict:
|
||||||
"""Set the voltage for the power supply unit of the Auradine miner.
|
"""Set the voltage for the power supply unit of the Auradine miner.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
voltage (float): The voltage level to set for the PSU.
|
voltage (float): The voltage level to set for the PSU.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary indicating the result of setting the PSU voltage.
|
dict: A dictionary indicating the result of setting the PSU voltage.
|
||||||
"""
|
"""
|
||||||
@@ -334,7 +334,7 @@ class AuradineWebAPI(BaseWebAPI):
|
|||||||
|
|
||||||
async def get_register(self) -> dict:
|
async def get_register(self) -> dict:
|
||||||
"""Retrieve registration information from the Auradine miner.
|
"""Retrieve registration information from the Auradine miner.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary containing the registration details.
|
dict: A dictionary containing the registration details.
|
||||||
"""
|
"""
|
||||||
@@ -342,10 +342,10 @@ class AuradineWebAPI(BaseWebAPI):
|
|||||||
|
|
||||||
async def set_register(self, company: str) -> dict:
|
async def set_register(self, company: str) -> dict:
|
||||||
"""Set the registration information for the Auradine miner.
|
"""Set the registration information for the Auradine miner.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
company (str): The company name to register the miner under.
|
company (str): The company name to register the miner under.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary indicating the result of the registration operation.
|
dict: A dictionary indicating the result of the registration operation.
|
||||||
"""
|
"""
|
||||||
@@ -353,7 +353,7 @@ class AuradineWebAPI(BaseWebAPI):
|
|||||||
|
|
||||||
async def reboot(self) -> dict:
|
async def reboot(self) -> dict:
|
||||||
"""Reboot the Auradine miner.
|
"""Reboot the Auradine miner.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary indicating the result of the reboot operation.
|
dict: A dictionary indicating the result of the reboot operation.
|
||||||
"""
|
"""
|
||||||
@@ -361,7 +361,7 @@ class AuradineWebAPI(BaseWebAPI):
|
|||||||
|
|
||||||
async def restart_gcminer(self) -> dict:
|
async def restart_gcminer(self) -> dict:
|
||||||
"""Restart the GCMiner application on the Auradine miner.
|
"""Restart the GCMiner application on the Auradine miner.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary indicating the result of the GCMiner restart operation.
|
dict: A dictionary indicating the result of the GCMiner restart operation.
|
||||||
"""
|
"""
|
||||||
@@ -369,7 +369,7 @@ class AuradineWebAPI(BaseWebAPI):
|
|||||||
|
|
||||||
async def restart_api_server(self) -> dict:
|
async def restart_api_server(self) -> dict:
|
||||||
"""Restart the API server on the Auradine miner.
|
"""Restart the API server on the Auradine miner.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary indicating the result of the API server restart operation.
|
dict: A dictionary indicating the result of the API server restart operation.
|
||||||
"""
|
"""
|
||||||
@@ -377,7 +377,7 @@ class AuradineWebAPI(BaseWebAPI):
|
|||||||
|
|
||||||
async def temperature(self) -> dict:
|
async def temperature(self) -> dict:
|
||||||
"""Retrieve the current temperature readings from the Auradine miner.
|
"""Retrieve the current temperature readings from the Auradine miner.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary containing temperature data.
|
dict: A dictionary containing temperature data.
|
||||||
"""
|
"""
|
||||||
@@ -385,11 +385,11 @@ class AuradineWebAPI(BaseWebAPI):
|
|||||||
|
|
||||||
async def timedate(self, ntp: str, timezone: str) -> dict:
|
async def timedate(self, ntp: str, timezone: str) -> dict:
|
||||||
"""Set the time and date settings for the Auradine miner.
|
"""Set the time and date settings for the Auradine miner.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
ntp (str): The NTP server to use for time synchronization.
|
ntp (str): The NTP server to use for time synchronization.
|
||||||
timezone (str): The timezone setting.
|
timezone (str): The timezone setting.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary indicating the result of setting the time and date.
|
dict: A dictionary indicating the result of setting the time and date.
|
||||||
"""
|
"""
|
||||||
@@ -397,7 +397,7 @@ class AuradineWebAPI(BaseWebAPI):
|
|||||||
|
|
||||||
async def get_token(self) -> dict:
|
async def get_token(self) -> dict:
|
||||||
"""Retrieve the current authentication token for the Auradine miner.
|
"""Retrieve the current authentication token for the Auradine miner.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary containing the authentication token.
|
dict: A dictionary containing the authentication token.
|
||||||
"""
|
"""
|
||||||
@@ -405,10 +405,10 @@ class AuradineWebAPI(BaseWebAPI):
|
|||||||
|
|
||||||
async def update_pools(self, pools: list[dict]) -> dict:
|
async def update_pools(self, pools: list[dict]) -> dict:
|
||||||
"""Update the mining pools configuration on the Auradine miner.
|
"""Update the mining pools configuration on the Auradine miner.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
pools (list[dict]): A list of dictionaries, each representing a pool configuration.
|
pools (list[dict]): A list of dictionaries, each representing a pool configuration.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary indicating the result of the update operation.
|
dict: A dictionary indicating the result of the update operation.
|
||||||
"""
|
"""
|
||||||
@@ -416,7 +416,7 @@ class AuradineWebAPI(BaseWebAPI):
|
|||||||
|
|
||||||
async def voltage(self) -> dict:
|
async def voltage(self) -> dict:
|
||||||
"""Retrieve the voltage settings of the Auradine miner.
|
"""Retrieve the voltage settings of the Auradine miner.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary containing the voltage details.
|
dict: A dictionary containing the voltage details.
|
||||||
"""
|
"""
|
||||||
@@ -424,7 +424,7 @@ class AuradineWebAPI(BaseWebAPI):
|
|||||||
|
|
||||||
async def get_ztp(self) -> dict:
|
async def get_ztp(self) -> dict:
|
||||||
"""Retrieve the zero-touch provisioning status from the Auradine miner.
|
"""Retrieve the zero-touch provisioning status from the Auradine miner.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary containing the ZTP status.
|
dict: A dictionary containing the ZTP status.
|
||||||
"""
|
"""
|
||||||
@@ -432,10 +432,10 @@ class AuradineWebAPI(BaseWebAPI):
|
|||||||
|
|
||||||
async def set_ztp(self, enable: bool) -> dict:
|
async def set_ztp(self, enable: bool) -> dict:
|
||||||
"""Enable or disable zero-touch provisioning (ZTP) on the Auradine miner.
|
"""Enable or disable zero-touch provisioning (ZTP) on the Auradine miner.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
enable (bool): True to enable ZTP, False to disable.
|
enable (bool): True to enable ZTP, False to disable.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: A dictionary indicating the result of the ZTP setting operation.
|
dict: A dictionary indicating the result of the ZTP setting operation.
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -1,30 +1,56 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import asyncio
|
||||||
import json
|
import json
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
|
|
||||||
from pyasic import settings
|
from pyasic import settings
|
||||||
from pyasic.web.antminer import AntminerModernWebAPI
|
from pyasic.web.base import BaseWebAPI
|
||||||
|
|
||||||
|
|
||||||
class MaraWebAPI(AntminerModernWebAPI):
|
class MaraWebAPI(BaseWebAPI):
|
||||||
def __init__(self, ip: str) -> None:
|
def __init__(self, ip: str) -> None:
|
||||||
self.am_commands = [
|
|
||||||
"get_miner_conf",
|
|
||||||
"set_miner_conf",
|
|
||||||
"blink",
|
|
||||||
"reboot",
|
|
||||||
"get_system_info",
|
|
||||||
"get_network_info",
|
|
||||||
"summary",
|
|
||||||
"get_blink_status",
|
|
||||||
"set_network_conf",
|
|
||||||
]
|
|
||||||
super().__init__(ip)
|
super().__init__(ip)
|
||||||
|
|
||||||
async def _send_mara_command(
|
async def multicommand(
|
||||||
|
self, *commands: str, ignore_errors: bool = False, allow_warning: bool = True
|
||||||
|
) -> dict:
|
||||||
|
async with httpx.AsyncClient(transport=settings.transport()) as client:
|
||||||
|
tasks = [
|
||||||
|
asyncio.create_task(self._handle_multicommand(client, command))
|
||||||
|
for command in commands
|
||||||
|
]
|
||||||
|
all_data = await asyncio.gather(*tasks)
|
||||||
|
|
||||||
|
data = {}
|
||||||
|
for item in all_data:
|
||||||
|
data.update(item)
|
||||||
|
|
||||||
|
data["multicommand"] = True
|
||||||
|
return data
|
||||||
|
|
||||||
|
async def _handle_multicommand(
|
||||||
|
self, client: httpx.AsyncClient, command: str
|
||||||
|
) -> dict:
|
||||||
|
auth = httpx.DigestAuth(self.username, self.pwd)
|
||||||
|
|
||||||
|
try:
|
||||||
|
url = f"http://{self.ip}:{self.port}/kaonsu/v1/{command}"
|
||||||
|
ret = await client.get(url, auth=auth)
|
||||||
|
except httpx.HTTPError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
if ret.status_code == 200:
|
||||||
|
try:
|
||||||
|
json_data = ret.json()
|
||||||
|
return {command: json_data}
|
||||||
|
except json.decoder.JSONDecodeError:
|
||||||
|
pass
|
||||||
|
return {command: {}}
|
||||||
|
|
||||||
|
async def send_command(
|
||||||
self,
|
self,
|
||||||
command: str | bytes,
|
command: str | bytes,
|
||||||
ignore_errors: bool = False,
|
ignore_errors: bool = False,
|
||||||
@@ -56,76 +82,66 @@ class MaraWebAPI(AntminerModernWebAPI):
|
|||||||
except json.decoder.JSONDecodeError:
|
except json.decoder.JSONDecodeError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
async def _send_am_command(
|
|
||||||
self,
|
|
||||||
command: str | bytes,
|
|
||||||
ignore_errors: bool = False,
|
|
||||||
allow_warning: bool = True,
|
|
||||||
privileged: bool = False,
|
|
||||||
**parameters: Any,
|
|
||||||
):
|
|
||||||
url = f"http://{self.ip}:{self.port}/cgi-bin/{command}.cgi"
|
|
||||||
auth = httpx.DigestAuth(self.username, self.pwd)
|
|
||||||
try:
|
|
||||||
async with httpx.AsyncClient(
|
|
||||||
transport=settings.transport(),
|
|
||||||
) as client:
|
|
||||||
if parameters:
|
|
||||||
data = await client.post(
|
|
||||||
url,
|
|
||||||
auth=auth,
|
|
||||||
timeout=settings.get("api_function_timeout", 3),
|
|
||||||
json=parameters,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
data = await client.get(url, auth=auth)
|
|
||||||
except httpx.HTTPError:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
if data.status_code == 200:
|
|
||||||
try:
|
|
||||||
return data.json()
|
|
||||||
except json.decoder.JSONDecodeError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
async def send_command(
|
|
||||||
self,
|
|
||||||
command: str | bytes,
|
|
||||||
ignore_errors: bool = False,
|
|
||||||
allow_warning: bool = True,
|
|
||||||
privileged: bool = False,
|
|
||||||
**parameters: Any,
|
|
||||||
) -> dict:
|
|
||||||
if command in self.am_commands:
|
|
||||||
return await self._send_am_command(
|
|
||||||
command,
|
|
||||||
ignore_errors=ignore_errors,
|
|
||||||
allow_warning=allow_warning,
|
|
||||||
privileged=privileged,
|
|
||||||
**parameters,
|
|
||||||
)
|
|
||||||
return await self._send_mara_command(
|
|
||||||
command,
|
|
||||||
ignore_errors=ignore_errors,
|
|
||||||
allow_warning=allow_warning,
|
|
||||||
privileged=privileged,
|
|
||||||
**parameters,
|
|
||||||
)
|
|
||||||
|
|
||||||
async def brief(self):
|
async def brief(self):
|
||||||
return await self.send_command("brief")
|
return await self.send_command("brief")
|
||||||
|
|
||||||
|
async def ping(self):
|
||||||
|
return await self.send_command("ping")
|
||||||
|
|
||||||
|
async def get_locate_miner(self):
|
||||||
|
return await self.send_command("locate_miner")
|
||||||
|
|
||||||
|
async def set_locate_miner(self, blinking: bool):
|
||||||
|
return await self.send_command("locate_miner", blinking=blinking)
|
||||||
|
|
||||||
|
async def reboot(self):
|
||||||
|
return await self.send_command("maintenance", type="reboot")
|
||||||
|
|
||||||
|
async def reset(self):
|
||||||
|
return await self.send_command("maintenance", type="reset")
|
||||||
|
|
||||||
|
async def reload(self):
|
||||||
|
return await self.send_command("maintenance", type="reload")
|
||||||
|
|
||||||
|
async def set_password(self, new_pwd: str):
|
||||||
|
return await self.send_command(
|
||||||
|
"maintenance",
|
||||||
|
type="passwd",
|
||||||
|
params={"curPwd": self.pwd, "confirmPwd": self.pwd, "newPwd": new_pwd},
|
||||||
|
)
|
||||||
|
|
||||||
|
async def get_network_config(self):
|
||||||
|
return await self.send_command("network_config")
|
||||||
|
|
||||||
|
async def set_network_config(self, **params):
|
||||||
|
return await self.send_command("network_config", **params)
|
||||||
|
|
||||||
|
async def get_miner_config(self):
|
||||||
|
return await self.send_command("miner_config")
|
||||||
|
|
||||||
|
async def set_miner_config(self, **params):
|
||||||
|
return await self.send_command("miner_config", **params)
|
||||||
|
|
||||||
|
async def fans(self):
|
||||||
|
return await self.send_command("fans")
|
||||||
|
|
||||||
|
async def log(self):
|
||||||
|
return await self.send_command("log")
|
||||||
|
|
||||||
async def overview(self):
|
async def overview(self):
|
||||||
return await self.send_command("overview")
|
return await self.send_command("overview")
|
||||||
|
|
||||||
async def connections(self):
|
async def connections(self):
|
||||||
return await self.send_command("connections")
|
return await self.send_command("connections")
|
||||||
|
|
||||||
|
async def controlboard_info(self):
|
||||||
|
return await self.send_command("controlboard_info")
|
||||||
|
|
||||||
async def event_chart(self):
|
async def event_chart(self):
|
||||||
return await self.send_command("event_chart")
|
return await self.send_command("event_chart")
|
||||||
|
|
||||||
async def hashboards(self):
|
async def hashboards(self):
|
||||||
return await self.send_command("hashboards")
|
return await self.send_command("hashboards")
|
||||||
|
|
||||||
async def mara_pools(self):
|
async def pools(self):
|
||||||
return await self._send_mara_command("pools")
|
return await self.send_command("pools")
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "pyasic"
|
name = "pyasic"
|
||||||
version = "0.54.20"
|
version = "0.55.4"
|
||||||
description = "A simplified and standardized interface for Bitcoin ASICs."
|
description = "A simplified and standardized interface for Bitcoin ASICs."
|
||||||
authors = ["UpstreamData <brett@upstreamdata.ca>"]
|
authors = ["UpstreamData <brett@upstreamdata.ca>"]
|
||||||
repository = "https://github.com/UpstreamData/pyasic"
|
repository = "https://github.com/UpstreamData/pyasic"
|
||||||
|
|||||||
@@ -33,3 +33,43 @@ class TestFanConfig(unittest.TestCase):
|
|||||||
conf = fan_mode()
|
conf = fan_mode()
|
||||||
am_conf = conf.as_am_modern()
|
am_conf = conf.as_am_modern()
|
||||||
self.assertEqual(conf, FanModeConfig.from_am_modern(am_conf))
|
self.assertEqual(conf, FanModeConfig.from_am_modern(am_conf))
|
||||||
|
|
||||||
|
def test_epic_deserialize_and_serialize(self):
|
||||||
|
for fan_mode in FanModeConfig:
|
||||||
|
with self.subTest(
|
||||||
|
msg=f"Test serialization and deserialization of epic fan config",
|
||||||
|
fan_mode=fan_mode,
|
||||||
|
):
|
||||||
|
conf = fan_mode()
|
||||||
|
epic_conf = conf.as_epic()
|
||||||
|
self.assertEqual(conf, FanModeConfig.from_epic(epic_conf))
|
||||||
|
|
||||||
|
def test_vnish_deserialize_and_serialize(self):
|
||||||
|
for fan_mode in FanModeConfig:
|
||||||
|
with self.subTest(
|
||||||
|
msg=f"Test serialization and deserialization of vnish fan config",
|
||||||
|
fan_mode=fan_mode,
|
||||||
|
):
|
||||||
|
conf = fan_mode()
|
||||||
|
vnish_conf = conf.as_vnish()
|
||||||
|
self.assertEqual(conf, FanModeConfig.from_vnish(vnish_conf))
|
||||||
|
|
||||||
|
def test_auradine_deserialize_and_serialize(self):
|
||||||
|
for fan_mode in FanModeConfig:
|
||||||
|
with self.subTest(
|
||||||
|
msg=f"Test serialization and deserialization of auradine fan config",
|
||||||
|
fan_mode=fan_mode,
|
||||||
|
):
|
||||||
|
conf = fan_mode()
|
||||||
|
aur_conf = conf.as_auradine()
|
||||||
|
self.assertEqual(conf, FanModeConfig.from_auradine(aur_conf))
|
||||||
|
|
||||||
|
def test_boser_deserialize_and_serialize(self):
|
||||||
|
for fan_mode in FanModeConfig:
|
||||||
|
with self.subTest(
|
||||||
|
msg=f"Test serialization and deserialization of boser fan config",
|
||||||
|
fan_mode=fan_mode,
|
||||||
|
):
|
||||||
|
conf = fan_mode()
|
||||||
|
boser_conf = conf.as_boser()
|
||||||
|
self.assertEqual(conf, FanModeConfig.from_boser(boser_conf))
|
||||||
|
|||||||
Reference in New Issue
Block a user