refactor: fix merge.

This commit is contained in:
UpstreamData
2024-01-15 13:09:23 -07:00
parent f1501718a3
commit e45e51ce65
19 changed files with 373 additions and 279 deletions

View File

@@ -17,7 +17,13 @@ from dataclasses import dataclass, field
from typing import Union
from pyasic.config.base import MinerConfigOption, MinerConfigValue
from pyasic.web.braiins_os.proto.braiins.bos.v1 import DpsPowerTarget, DpsTarget, Hours
from pyasic.web.braiins_os.proto.braiins.bos.v1 import (
DpsPowerTarget,
DpsTarget,
Hours,
Power,
SetDpsRequest,
)
@dataclass
@@ -37,13 +43,8 @@ class PowerScalingShutdownEnabled(MinerConfigValue):
return cfg
def as_bos_grpc(self) -> dict:
cfg = {"enable_shutdown ": True}
if self.duration is not None:
cfg["shutdown_duration"] = Hours(self.duration)
return cfg
def as_boser(self) -> dict:
return {"enable_shutdown": True, "shutdown_duration": self.duration}
@dataclass
@@ -57,7 +58,7 @@ class PowerScalingShutdownDisabled(MinerConfigValue):
def as_bosminer(self) -> dict:
return {"shutdown_enabled": False}
def as_bos_grpc(self) -> dict:
def as_boser(self) -> dict:
return {"enable_shutdown ": False}
@@ -88,6 +89,19 @@ class PowerScalingShutdown(MinerConfigOption):
return cls.disabled()
return None
@classmethod
def from_boser(cls, power_scaling_conf: dict):
sd_enabled = power_scaling_conf.get("shutdownEnabled")
if sd_enabled is not None:
if sd_enabled:
try:
return cls.enabled(power_scaling_conf["shutdownDuration"]["hours"])
except KeyError:
return cls.enabled()
else:
return cls.disabled()
return None
@dataclass
class PowerScalingEnabled(MinerConfigValue):
@@ -133,20 +147,19 @@ class PowerScalingEnabled(MinerConfigValue):
return {"power_scaling": cfg}
def as_bos_grpc(self) -> dict:
cfg = {"enable": True}
target_conf = {}
if self.power_step is not None:
target_conf["power_step"] = self.power_step
if self.minimum_power is not None:
target_conf["min_power_target"] = self.minimum_power
cfg["target"] = DpsTarget(power_target=DpsPowerTarget(**target_conf))
if self.shutdown_enabled is not None:
cfg = {**cfg, **self.shutdown_enabled.as_bos_grpc()}
return {"dps": cfg}
def as_boser(self) -> dict:
return {
"set_dps": SetDpsRequest(
enable=True,
**self.shutdown_enabled.as_boser(),
target=DpsTarget(
power_target=DpsPowerTarget(
power_step=Power(self.power_step),
min_power_target=Power(self.minimum_power),
)
),
),
}
@dataclass
@@ -187,3 +200,21 @@ class PowerScalingConfig(MinerConfigOption):
return cls.disabled()
return cls.default()
@classmethod
def from_boser(cls, grpc_miner_conf: dict):
try:
dps_conf = grpc_miner_conf["dps"]
if not dps_conf.get("enabled", False):
return cls.disabled()
except LookupError:
return cls.default()
conf = {}
conf["shutdown_enabled"] = PowerScalingShutdown.from_boser(dps_conf)
if dps_conf.get("minPowerTarget") is not None:
conf["minimum_power"] = dps_conf["minPowerTarget"]["watt"]
if dps_conf.get("powerStep") is not None:
conf["power_step"] = dps_conf["powerStep"]["watt"]
return cls.enabled(**conf)

View File

@@ -41,7 +41,7 @@ class HiveonT9(Hiveon, T9):
except (TypeError, ValueError, asyncssh.Error, OSError, AttributeError):
pass
async def get_hashboards(self, api_stats: dict = None) -> List[HashBoard]:
async def _get_hashboards(self, api_stats: dict = None) -> List[HashBoard]:
hashboards = [
HashBoard(slot=board, expected_chips=self.expected_chips)
for board in range(self.expected_hashboards)
@@ -83,7 +83,7 @@ class HiveonT9(Hiveon, T9):
return hashboards
async def get_wattage(self, api_stats: dict = None) -> Optional[int]:
async def _get_wattage(self, api_stats: dict = None) -> Optional[int]:
if not api_stats:
try:
api_stats = await self.api.stats()
@@ -100,7 +100,7 @@ class HiveonT9(Hiveon, T9):
# parse wattage position out of raw data
return round(float(wattage_raw.split(" ")[0]))
async def get_env_temp(self, api_stats: dict = None) -> Optional[float]:
async def _get_env_temp(self, api_stats: dict = None) -> Optional[float]:
env_temp_list = []
board_map = {
0: [2, 9, 10],

View File

@@ -45,51 +45,52 @@ BOSMINER_DATA_LOC = DataLocations(
"_get_mac",
[WebAPICommand("web_net_conf", "admin/network/iface_status/lan")],
),
str(DataOptions.MODEL): DataFunction("get_model"),
str(DataOptions.API_VERSION): DataFunction(
"get_api_ver", [RPCAPICommand("api_version", "version")]
"_get_api_ver", [RPCAPICommand("api_version", "version")]
),
str(DataOptions.FW_VERSION): DataFunction("get_fw_ver"),
str(DataOptions.HOSTNAME): DataFunction("get_hostname"),
str(DataOptions.FW_VERSION): DataFunction(
"_get_fw_ver", [WebAPICommand("web_bos_info", "bos/info")]
),
str(DataOptions.HOSTNAME): DataFunction("_get_hostname"),
str(DataOptions.HASHRATE): DataFunction(
"get_hashrate",
"_get_hashrate",
[RPCAPICommand("api_summary", "summary")],
),
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
"get_expected_hashrate", [RPCAPICommand("api_devs", "devs")]
"_get_expected_hashrate", [RPCAPICommand("api_devs", "devs")]
),
str(DataOptions.HASHBOARDS): DataFunction(
"get_hashboards",
"_get_hashboards",
[
RPCAPICommand("api_temps", "temps"),
RPCAPICommand("api_devdetails", "devdetails"),
RPCAPICommand("api_devs", "devs"),
],
),
str(DataOptions.ENVIRONMENT_TEMP): DataFunction("get_env_temp"),
str(DataOptions.ENVIRONMENT_TEMP): DataFunction("_get_env_temp"),
str(DataOptions.WATTAGE): DataFunction(
"get_wattage",
"_get_wattage",
[RPCAPICommand("api_tunerstatus", "tunerstatus")],
),
str(DataOptions.WATTAGE_LIMIT): DataFunction(
"get_wattage_limit",
"_get_wattage_limit",
[RPCAPICommand("api_tunerstatus", "tunerstatus")],
),
str(DataOptions.FANS): DataFunction(
"get_fans",
"_get_fans",
[RPCAPICommand("api_fans", "fans")],
),
str(DataOptions.FAN_PSU): DataFunction("get_fan_psu"),
str(DataOptions.FAN_PSU): DataFunction("_get_fan_psu"),
str(DataOptions.ERRORS): DataFunction(
"get_errors",
"_get_errors",
[RPCAPICommand("api_tunerstatus", "tunerstatus")],
),
str(DataOptions.FAULT_LIGHT): DataFunction("get_fault_light"),
str(DataOptions.FAULT_LIGHT): DataFunction("_get_fault_light"),
str(DataOptions.IS_MINING): DataFunction(
"is_mining", [RPCAPICommand("api_devdetails", "devdetails")]
"_is_mining", [RPCAPICommand("api_devdetails", "devdetails")]
),
str(DataOptions.UPTIME): DataFunction(
"get_uptime", [RPCAPICommand("api_summary", "summary")]
"_get_uptime", [RPCAPICommand("api_summary", "summary")]
),
str(DataOptions.CONFIG): DataFunction("get_config"),
}
@@ -288,16 +289,17 @@ class BOSMiner(BaseMiner):
gateway: str,
subnet_mask: str = "255.255.255.0",
):
cfg_data_lan = (
"config interface 'lan'\n\toption type 'bridge'\n\toption ifname 'eth0'\n\toption proto 'static'\n\toption ipaddr '"
+ ip
+ "'\n\toption netmask '"
+ subnet_mask
+ "'\n\toption gateway '"
+ gateway
+ "'\n\toption dns '"
+ dns
+ "'"
cfg_data_lan = "\n\t".join(
[
"config interface 'lan'",
"option type 'bridge'",
"option ifname 'eth0'",
"option proto 'static'",
f"option ipaddr '{ip}'",
f"option netmask '{subnet_mask}'",
f"option gateway '{gateway}'",
f"option dns '{dns}'",
]
)
data = await self.send_ssh_command("cat /etc/config/network")
@@ -313,7 +315,14 @@ class BOSMiner(BaseMiner):
await conn.run("echo '" + config + "' > /etc/config/network")
async def set_dhcp(self):
cfg_data_lan = "config interface 'lan'\n\toption type 'bridge'\n\toption ifname 'eth0'\n\toption proto 'dhcp'"
cfg_data_lan = "\n\t".join(
[
"config interface 'lan'",
"option type 'bridge'",
"option ifname 'eth0'",
"option proto 'dhcp'",
]
)
data = await self.send_ssh_command("cat /etc/config/network")
split_data = data.split("\n\n")
@@ -331,12 +340,10 @@ class BOSMiner(BaseMiner):
### DATA GATHERING FUNCTIONS (get_{some_data}) ###
##################################################
async def get_mac(self, web_net_conf: Union[dict, list] = None) -> Optional[str]:
async def _get_mac(self, web_net_conf: Union[dict, list] = None) -> Optional[str]:
if not web_net_conf:
try:
web_net_conf = await self.web.luci.send_command(
"admin/network/iface_status/lan"
)
web_net_conf = await self.web.luci.get_net_conf()
except APIError:
pass
@@ -354,21 +361,7 @@ class BOSMiner(BaseMiner):
# if result:
# return result.upper().strip()
async def get_model(self) -> Optional[str]:
if self.model is not None:
return self.model + " (BOS)"
return "? (BOS)"
async def get_version(
self, api_version: dict = None, graphql_version: dict = None
) -> Tuple[Optional[str], Optional[str]]:
miner_version = namedtuple("MinerVersion", "api_ver fw_ver")
api_ver_t = asyncio.create_task(self.get_api_ver(api_version))
fw_ver_t = asyncio.create_task(self.get_fw_ver())
await asyncio.gather(api_ver_t, fw_ver_t)
return miner_version(api_ver=api_ver_t.result(), fw_ver=fw_ver_t.result())
async def get_api_ver(self, api_version: dict = None) -> Optional[str]:
async def _get_api_ver(self, api_version: dict = None) -> Optional[str]:
if not api_version:
try:
api_version = await self.api.version()
@@ -386,19 +379,28 @@ class BOSMiner(BaseMiner):
return self.api_ver
async def get_fw_ver(self) -> Optional[str]:
fw_ver = await self.send_ssh_command("cat /etc/bos_version")
async def _get_fw_ver(self, web_bos_info: dict) -> Optional[str]:
if web_bos_info is None:
try:
web_bos_info = await self.web.luci.get_bos_info()
except APIError:
return None
# if we get the version data, parse it
if fw_ver is not None:
ver = fw_ver.split("-")[5]
if isinstance(web_bos_info, dict):
if "bos/info" in web_bos_info.keys():
web_bos_info = web_bos_info["bos/info"]
try:
ver = web_bos_info["version"].split("-")[5]
if "." in ver:
self.fw_ver = ver
logging.debug(f"Found version for {self.ip}: {self.fw_ver}")
except (LookupError, AttributeError):
return None
return self.fw_ver
async def get_hostname(self) -> Union[str, None]:
async def _get_hostname(self) -> Union[str, None]:
try:
hostname = (
await self.send_ssh_command("cat /proc/sys/kernel/hostname")
@@ -408,7 +410,7 @@ class BOSMiner(BaseMiner):
return None
return hostname
async def get_hashrate(self, api_summary: dict = None) -> Optional[float]:
async def _get_hashrate(self, api_summary: dict = None) -> Optional[float]:
# get hr from API
if not api_summary:
try:
@@ -422,7 +424,7 @@ class BOSMiner(BaseMiner):
except (KeyError, IndexError, ValueError, TypeError):
pass
async def get_hashboards(
async def _get_hashboards(
self,
api_temps: dict = None,
api_devdetails: dict = None,
@@ -495,10 +497,10 @@ class BOSMiner(BaseMiner):
return hashboards
async def get_env_temp(self) -> Optional[float]:
async def _get_env_temp(self) -> Optional[float]:
return None
async def get_wattage(self, api_tunerstatus: dict = None) -> Optional[int]:
async def _get_wattage(self, api_tunerstatus: dict = None) -> Optional[int]:
if not api_tunerstatus:
try:
api_tunerstatus = await self.api.tunerstatus()
@@ -513,7 +515,7 @@ class BOSMiner(BaseMiner):
except LookupError:
pass
async def get_wattage_limit(self, api_tunerstatus: dict = None) -> Optional[int]:
async def _get_wattage_limit(self, api_tunerstatus: dict = None) -> Optional[int]:
if not api_tunerstatus:
try:
api_tunerstatus = await self.api.tunerstatus()
@@ -526,7 +528,7 @@ class BOSMiner(BaseMiner):
except LookupError:
pass
async def get_fans(self, api_fans: dict = None) -> List[Fan]:
async def _get_fans(self, api_fans: dict = None) -> List[Fan]:
if not api_fans:
try:
api_fans = await self.api.fans()
@@ -543,10 +545,10 @@ class BOSMiner(BaseMiner):
return fans
return [Fan() for _ in range(self.fan_count)]
async def get_fan_psu(self) -> Optional[int]:
async def _get_fan_psu(self) -> Optional[int]:
return None
async def get_errors(self, api_tunerstatus: dict = None) -> List[MinerErrorData]:
async def _get_errors(self, api_tunerstatus: dict = None) -> List[MinerErrorData]:
if not api_tunerstatus:
try:
api_tunerstatus = await self.api.tunerstatus()
@@ -576,7 +578,7 @@ class BOSMiner(BaseMiner):
except (KeyError, IndexError):
pass
async def get_fault_light(self, graphql_fault_light: dict = None) -> bool:
async def _get_fault_light(self) -> bool:
if self.light:
return self.light
try:
@@ -590,7 +592,7 @@ class BOSMiner(BaseMiner):
except (TypeError, AttributeError):
return self.light
async def get_expected_hashrate(self, api_devs: dict = None) -> Optional[float]:
async def _get_expected_hashrate(self, api_devs: dict = None) -> Optional[float]:
if not api_devs:
try:
api_devs = await self.api.devs()
@@ -616,7 +618,7 @@ class BOSMiner(BaseMiner):
except (IndexError, KeyError):
pass
async def is_mining(self, api_devdetails: dict = None) -> Optional[bool]:
async def _is_mining(self, api_devdetails: dict = None) -> Optional[bool]:
if not api_devdetails:
try:
api_devdetails = await self.api.send_command(
@@ -631,7 +633,7 @@ class BOSMiner(BaseMiner):
except LookupError:
pass
async def get_uptime(self, api_summary: dict = None) -> Optional[int]:
async def _get_uptime(self, api_summary: dict = None) -> Optional[int]:
if not api_summary:
try:
api_summary = await self.api.summary()
@@ -648,7 +650,7 @@ class BOSMiner(BaseMiner):
BOSER_DATA_LOC = DataLocations(
**{
str(DataOptions.MAC): DataFunction(
"get_mac",
"_get_mac",
[GRPCCommand("grpc_miner_details", "get_miner_details")],
),
str(DataOptions.API_VERSION): DataFunction(
@@ -720,7 +722,6 @@ class BOSer(BaseMiner):
# static data
self.api_type = "BOSMiner"
self.fw_str = "BOS"
# data gathering locations
self.data_locations = BOSER_DATA_LOC
# autotuning/shutdown support
@@ -770,41 +771,27 @@ class BOSer(BaseMiner):
return False
async def get_config(self) -> MinerConfig:
logging.debug(f"{self}: Getting config.")
grpc_conf = await self.web.grpc.get_miner_configuration()
try:
conn = await self._get_ssh_connection()
except ConnectionError:
conn = None
if conn:
async with conn:
# good ol' BBB compatibility :/
toml_data = toml.loads(
(await conn.run("cat /etc/bosminer.toml")).stdout
)
logging.debug(f"{self}: Converting config file.")
cfg = MinerConfig.from_bosminer(toml_data)
self.config = cfg
return self.config
return MinerConfig.from_boser(grpc_conf)
async def send_config(self, config: MinerConfig, user_suffix: str = None) -> None:
raise NotImplementedError
logging.debug(f"{self}: Sending config.")
self.config = config
raise NotImplementedError
async def set_power_limit(self, wattage: int) -> bool:
try:
cfg = await self.get_config()
if cfg is None:
return False
cfg.mining_mode = MiningModePowerTune(wattage)
await self.send_config(cfg)
except Exception as e:
logging.warning(f"{self} set_power_limit: {e}")
result = await self.web.grpc.set_power_target(wattage)
except APIError:
return False
else:
return True
try:
if result["powerTarget"]["watt"] == wattage:
return True
except KeyError:
pass
return False
##################################################
### DATA GATHERING FUNCTIONS (get_{some_data}) ###
@@ -823,20 +810,11 @@ class BOSer(BaseMiner):
except (LookupError, TypeError):
pass
async def get_model(self) -> Optional[str]:
if self.raw_model is not None:
return self.raw_model + " (BOS)"
async def _get_model(self) -> Optional[str]:
if self.model is not None:
return self.model + " (BOS)"
return "? (BOS)"
async def get_version(
self, api_version: dict = None, graphql_version: dict = None
) -> Tuple[Optional[str], Optional[str]]:
# check if version is cached
miner_version = namedtuple("MinerVersion", "api_ver fw_ver")
api_ver = await self.get_api_ver(api_version)
fw_ver = await self.get_fw_ver(graphql_version)
return miner_version(api_ver, fw_ver)
async def _get_api_ver(self, api_version: dict = None) -> Optional[str]:
if not api_version:
try:
@@ -902,10 +880,10 @@ class BOSer(BaseMiner):
if api_summary:
try:
return round(float(api_summary["SUMMARY"][0]["MHS 1m"] / 1000000), 2)
except (LookupError, ValueError, TypeError):
except (KeyError, IndexError, ValueError, TypeError):
pass
async def get_expected_hashrate(
async def _get_expected_hashrate(
self, grpc_miner_details: dict = None
) -> Optional[float]:
if not grpc_miner_details:
@@ -920,7 +898,7 @@ class BOSer(BaseMiner):
except LookupError:
pass
async def get_hashboards(self, grpc_hashboards: dict = None):
async def _get_hashboards(self, grpc_hashboards: dict = None):
hashboards = [
HashBoard(slot=i, expected_chips=self.expected_chips)
for i in range(self.expected_hashboards)
@@ -991,7 +969,7 @@ class BOSer(BaseMiner):
except KeyError:
pass
async def get_fans(self, grpc_cooling_state: dict = None) -> List[Fan]:
async def _get_fans(self, grpc_cooling_state: dict = None) -> List[Fan]:
if grpc_cooling_state is None:
try:
grpc_cooling_state = self.web.grpc.get_cooling_state()
@@ -1000,13 +978,13 @@ class BOSer(BaseMiner):
if grpc_cooling_state:
fans = []
for n in range(self.expected_fans):
for n in range(self.fan_count):
try:
fans.append(Fan(grpc_cooling_state["fans"][n]["rpm"]))
except LookupError:
except (IndexError, KeyError):
pass
return fans
return [Fan() for _ in range(self.expected_fans)]
return [Fan() for _ in range(self.fan_count)]
async def _get_fan_psu(self) -> Optional[int]:
return None

View File

@@ -28,42 +28,41 @@ from pyasic.miners.base import DataFunction, DataLocations, DataOptions, RPCAPIC
AVALON_DATA_LOC = DataLocations(
**{
str(DataOptions.MAC): DataFunction(
"get_mac", [RPCAPICommand("api_version", "version")]
"_get_mac", [RPCAPICommand("api_version", "version")]
),
str(DataOptions.MODEL): DataFunction("get_model"),
str(DataOptions.API_VERSION): DataFunction(
"get_api_ver", [RPCAPICommand("api_version", "version")]
"_get_api_ver", [RPCAPICommand("api_version", "version")]
),
str(DataOptions.FW_VERSION): DataFunction(
"get_fw_ver", [RPCAPICommand("api_version", "version")]
"_get_fw_ver", [RPCAPICommand("api_version", "version")]
),
str(DataOptions.HOSTNAME): DataFunction("get_hostname"),
str(DataOptions.HOSTNAME): DataFunction("_get_hostname"),
str(DataOptions.HASHRATE): DataFunction(
"get_hashrate", [RPCAPICommand("api_devs", "devs")]
"_get_hashrate", [RPCAPICommand("api_devs", "devs")]
),
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
"get_expected_hashrate", [RPCAPICommand("api_stats", "stats")]
"_get_expected_hashrate", [RPCAPICommand("api_stats", "stats")]
),
str(DataOptions.HASHBOARDS): DataFunction(
"get_hashboards", [RPCAPICommand("api_stats", "stats")]
"_get_hashboards", [RPCAPICommand("api_stats", "stats")]
),
str(DataOptions.ENVIRONMENT_TEMP): DataFunction(
"get_env_temp", [RPCAPICommand("api_stats", "stats")]
"_get_env_temp", [RPCAPICommand("api_stats", "stats")]
),
str(DataOptions.WATTAGE): DataFunction("get_wattage"),
str(DataOptions.WATTAGE): DataFunction("_get_wattage"),
str(DataOptions.WATTAGE_LIMIT): DataFunction(
"get_wattage_limit", [RPCAPICommand("api_stats", "stats")]
"_get_wattage_limit", [RPCAPICommand("api_stats", "stats")]
),
str(DataOptions.FANS): DataFunction(
"get_fans", [RPCAPICommand("api_stats", "stats")]
"_get_fans", [RPCAPICommand("api_stats", "stats")]
),
str(DataOptions.FAN_PSU): DataFunction("get_fan_psu"),
str(DataOptions.ERRORS): DataFunction("get_errors"),
str(DataOptions.FAN_PSU): DataFunction("_get_fan_psu"),
str(DataOptions.ERRORS): DataFunction("_get_errors"),
str(DataOptions.FAULT_LIGHT): DataFunction(
"get_fault_light", [RPCAPICommand("api_stats", "stats")]
"_get_fault_light", [RPCAPICommand("api_stats", "stats")]
),
str(DataOptions.IS_MINING): DataFunction("is_mining"),
str(DataOptions.UPTIME): DataFunction("get_uptime"),
str(DataOptions.IS_MINING): DataFunction("_is_mining"),
str(DataOptions.UPTIME): DataFunction("_get_uptime"),
str(DataOptions.CONFIG): DataFunction("get_config"),
}
)
@@ -174,7 +173,7 @@ class CGMinerAvalon(CGMiner):
### DATA GATHERING FUNCTIONS (get_{some_data}) ###
##################################################
async def get_mac(self, api_version: dict = None) -> Optional[str]:
async def _get_mac(self, api_version: dict = None) -> Optional[str]:
if not api_version:
try:
api_version = await self.api.version()
@@ -192,7 +191,7 @@ class CGMinerAvalon(CGMiner):
except (KeyError, ValueError):
pass
async def get_hostname(self) -> Optional[str]:
async def _get_hostname(self) -> Optional[str]:
return None
# if not mac:
# mac = await self.get_mac()
@@ -200,7 +199,7 @@ class CGMinerAvalon(CGMiner):
# if mac:
# return f"Avalon{mac.replace(':', '')[-6:]}"
async def get_hashrate(self, api_devs: dict = None) -> Optional[float]:
async def _get_hashrate(self, api_devs: dict = None) -> Optional[float]:
if not api_devs:
try:
api_devs = await self.api.devs()
@@ -213,7 +212,7 @@ class CGMinerAvalon(CGMiner):
except (KeyError, IndexError, ValueError, TypeError):
pass
async def get_hashboards(self, api_stats: dict = None) -> List[HashBoard]:
async def _get_hashboards(self, api_stats: dict = None) -> List[HashBoard]:
hashboards = [
HashBoard(slot=i, expected_chips=self.expected_chips)
for i in range(self.expected_hashboards)
@@ -261,7 +260,7 @@ class CGMinerAvalon(CGMiner):
return hashboards
async def get_expected_hashrate(self, api_stats: dict = None) -> Optional[float]:
async def _get_expected_hashrate(self, api_stats: dict = None) -> Optional[float]:
if not api_stats:
try:
api_stats = await self.api.stats()
@@ -276,7 +275,7 @@ class CGMinerAvalon(CGMiner):
except (IndexError, KeyError, ValueError, TypeError):
pass
async def get_env_temp(self, api_stats: dict = None) -> Optional[float]:
async def _get_env_temp(self, api_stats: dict = None) -> Optional[float]:
if not api_stats:
try:
api_stats = await self.api.stats()
@@ -291,10 +290,10 @@ class CGMinerAvalon(CGMiner):
except (IndexError, KeyError, ValueError, TypeError):
pass
async def get_wattage(self) -> Optional[int]:
async def _get_wattage(self) -> Optional[int]:
return None
async def get_wattage_limit(self, api_stats: dict = None) -> Optional[int]:
async def _get_wattage_limit(self, api_stats: dict = None) -> Optional[int]:
if not api_stats:
try:
api_stats = await self.api.stats()
@@ -309,7 +308,7 @@ class CGMinerAvalon(CGMiner):
except (IndexError, KeyError, ValueError, TypeError):
pass
async def get_fans(self, api_stats: dict = None) -> List[Fan]:
async def _get_fans(self, api_stats: dict = None) -> List[Fan]:
if not api_stats:
try:
api_stats = await self.api.stats()
@@ -331,10 +330,10 @@ class CGMinerAvalon(CGMiner):
pass
return fans_data
async def get_errors(self) -> List[MinerErrorData]:
async def _get_errors(self) -> List[MinerErrorData]:
return []
async def get_fault_light(self, api_stats: dict = None) -> bool: # noqa
async def _get_fault_light(self, api_stats: dict = None) -> bool: # noqa
if self.light:
return self.light
if not api_stats:
@@ -363,8 +362,8 @@ class CGMinerAvalon(CGMiner):
pass
return False
async def is_mining(self, *args, **kwargs) -> Optional[bool]:
async def _is_mining(self, *args, **kwargs) -> Optional[bool]:
return None
async def get_uptime(self) -> Optional[int]:
async def _get_uptime(self) -> Optional[int]:
return None

View File

@@ -23,39 +23,38 @@ from pyasic.miners.base import DataFunction, DataLocations, DataOptions, RPCAPIC
HIVEON_DATA_LOC = DataLocations(
**{
str(DataOptions.MAC): DataFunction("get_mac"),
str(DataOptions.MODEL): DataFunction("get_model"),
str(DataOptions.API_VERSION): DataFunction(
"get_api_ver", [RPCAPICommand("api_version", "version")]
"_get_api_ver", [RPCAPICommand("api_version", "version")]
),
str(DataOptions.FW_VERSION): DataFunction(
"get_fw_ver", [RPCAPICommand("api_version", "version")]
"_get_fw_ver", [RPCAPICommand("api_version", "version")]
),
str(DataOptions.HOSTNAME): DataFunction("get_hostname"),
str(DataOptions.HOSTNAME): DataFunction("_get_hostname"),
str(DataOptions.HASHRATE): DataFunction(
"get_hashrate", [RPCAPICommand("api_summary", "summary")]
"_get_hashrate", [RPCAPICommand("api_summary", "summary")]
),
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
"get_expected_hashrate", [RPCAPICommand("api_stats", "stats")]
"_get_expected_hashrate", [RPCAPICommand("api_stats", "stats")]
),
str(DataOptions.HASHBOARDS): DataFunction(
"get_hashboards", [RPCAPICommand("api_stats", "stats")]
"_get_hashboards", [RPCAPICommand("api_stats", "stats")]
),
str(DataOptions.ENVIRONMENT_TEMP): DataFunction(
"get_env_temp", [RPCAPICommand("api_stats", "stats")]
"_get_env_temp", [RPCAPICommand("api_stats", "stats")]
),
str(DataOptions.WATTAGE): DataFunction(
"get_wattage", [RPCAPICommand("api_stats", "stats")]
"_get_wattage", [RPCAPICommand("api_stats", "stats")]
),
str(DataOptions.WATTAGE_LIMIT): DataFunction("get_wattage_limit"),
str(DataOptions.FANS): DataFunction(
"get_fans", [RPCAPICommand("api_stats", "stats")]
"_get_fans", [RPCAPICommand("api_stats", "stats")]
),
str(DataOptions.FAN_PSU): DataFunction("get_fan_psu"),
str(DataOptions.ERRORS): DataFunction("get_errors"),
str(DataOptions.FAULT_LIGHT): DataFunction("get_fault_light"),
str(DataOptions.IS_MINING): DataFunction("is_mining"),
str(DataOptions.FAN_PSU): DataFunction("_get_fan_psu"),
str(DataOptions.ERRORS): DataFunction("_get_errors"),
str(DataOptions.FAULT_LIGHT): DataFunction("_get_fault_light"),
str(DataOptions.IS_MINING): DataFunction("_is_mining"),
str(DataOptions.UPTIME): DataFunction(
"get_uptime", [RPCAPICommand("api_stats", "stats")]
"_get_uptime", [RPCAPICommand("api_stats", "stats")]
),
str(DataOptions.CONFIG): DataFunction("get_config"),
}
@@ -71,16 +70,11 @@ class Hiveon(BMMiner):
# data gathering locations
self.data_locations = HIVEON_DATA_LOC
async def get_model(self) -> Optional[str]:
if self.model is not None:
return self.model + " (Hiveon)"
return "? (Hiveon)"
async def get_hashboards(self, api_stats: dict = None) -> List[HashBoard]:
async def _get_hashboards(self, api_stats: dict = None) -> List[HashBoard]:
pass
async def get_wattage(self, api_stats: dict = None) -> Optional[int]:
async def _get_wattage(self, api_stats: dict = None) -> Optional[int]:
pass
async def get_env_temp(self, api_stats: dict = None) -> Optional[float]:
async def _get_env_temp(self, api_stats: dict = None) -> Optional[float]:
pass

View File

@@ -33,68 +33,67 @@ from pyasic.web.innosilicon import InnosiliconWebAPI
INNOSILICON_DATA_LOC = DataLocations(
**{
str(DataOptions.MAC): DataFunction(
"get_mac",
"_get_mac",
[
WebAPICommand("web_get_all", "getAll"),
WebAPICommand("web_overview", "overview"),
],
),
str(DataOptions.MODEL): DataFunction("get_model"),
str(DataOptions.API_VERSION): DataFunction(
"get_api_ver", [RPCAPICommand("api_version", "version")]
"_get_api_ver", [RPCAPICommand("api_version", "version")]
),
str(DataOptions.FW_VERSION): DataFunction(
"get_fw_ver", [RPCAPICommand("api_version", "version")]
"_get_fw_ver", [RPCAPICommand("api_version", "version")]
),
str(DataOptions.HOSTNAME): DataFunction("get_hostname"),
str(DataOptions.HOSTNAME): DataFunction("_get_hostname"),
str(DataOptions.HASHRATE): DataFunction(
"get_hashrate",
"_get_hashrate",
[
RPCAPICommand("api_summary", "summary"),
WebAPICommand("web_get_all", "getAll"),
],
),
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
"get_expected_hashrate",
"_get_expected_hashrate",
),
str(DataOptions.HASHBOARDS): DataFunction(
"get_hashboards",
"_get_hashboards",
[
RPCAPICommand("api_stats", "stats"),
WebAPICommand("web_get_all", "getAll"),
],
),
str(DataOptions.ENVIRONMENT_TEMP): DataFunction("get_env_temp"),
str(DataOptions.ENVIRONMENT_TEMP): DataFunction("_get_env_temp"),
str(DataOptions.WATTAGE): DataFunction(
"get_wattage",
"_get_wattage",
[
WebAPICommand("web_get_all", "getAll"),
RPCAPICommand("api_stats", "stats"),
],
),
str(DataOptions.WATTAGE_LIMIT): DataFunction(
"get_wattage_limit",
"_get_wattage_limit",
[
WebAPICommand("web_get_all", "getAll"),
],
),
str(DataOptions.FANS): DataFunction(
"get_fans",
"_get_fans",
[
WebAPICommand("web_get_all", "getAll"),
],
),
str(DataOptions.FAN_PSU): DataFunction("get_fan_psu"),
str(DataOptions.FAN_PSU): DataFunction("_get_fan_psu"),
str(DataOptions.ERRORS): DataFunction(
"get_errors",
"_get_errors",
[
WebAPICommand("web_get_error_detail", "getErrorDetail"),
],
),
str(DataOptions.FAULT_LIGHT): DataFunction("get_fault_light"),
str(DataOptions.IS_MINING): DataFunction("is_mining"),
str(DataOptions.FAULT_LIGHT): DataFunction("_get_fault_light"),
str(DataOptions.IS_MINING): DataFunction("_is_mining"),
str(DataOptions.UPTIME): DataFunction(
"get_uptime", [RPCAPICommand("api_stats", "stats")]
"_get_uptime", [RPCAPICommand("api_stats", "stats")]
),
str(DataOptions.CONFIG): DataFunction("get_config"),
}
@@ -176,7 +175,7 @@ class Innosilicon(CGMiner):
### DATA GATHERING FUNCTIONS (get_{some_data}) ###
##################################################
async def get_mac(
async def _get_mac(
self, web_get_all: dict = None, web_overview: dict = None
) -> Optional[str]:
if web_get_all:
@@ -202,7 +201,7 @@ class Innosilicon(CGMiner):
except KeyError:
pass
async def get_hashrate(
async def _get_hashrate(
self, api_summary: dict = None, web_get_all: dict = None
) -> Optional[float]:
if web_get_all:
@@ -234,7 +233,7 @@ class Innosilicon(CGMiner):
except (KeyError, IndexError):
pass
async def get_hashboards(
async def _get_hashboards(
self, api_stats: dict = None, web_get_all: dict = None
) -> List[HashBoard]:
if web_get_all:
@@ -292,7 +291,7 @@ class Innosilicon(CGMiner):
return hashboards
async def get_wattage(
async def _get_wattage(
self, web_get_all: dict = None, api_stats: dict = None
) -> Optional[int]:
if web_get_all:
@@ -329,7 +328,7 @@ class Innosilicon(CGMiner):
wattage = int(wattage)
return wattage
async def get_fans(self, web_get_all: dict = None) -> List[Fan]:
async def _get_fans(self, web_get_all: dict = None) -> List[Fan]:
if web_get_all:
web_get_all = web_get_all["all"]
@@ -354,7 +353,7 @@ class Innosilicon(CGMiner):
return fans
async def get_errors(
async def _get_errors(
self, web_get_error_detail: dict = None
) -> List[MinerErrorData]:
errors = []
@@ -377,7 +376,7 @@ class Innosilicon(CGMiner):
errors.append(InnosiliconError(error_code=err))
return errors
async def get_wattage_limit(self, web_get_all: dict = None) -> Optional[int]:
async def _get_wattage_limit(self, web_get_all: dict = None) -> Optional[int]:
if web_get_all:
web_get_all = web_get_all["all"]
@@ -400,5 +399,5 @@ class Innosilicon(CGMiner):
limit = 1250 + (250 * level)
return limit
async def get_expected_hashrate(self) -> Optional[float]:
async def _get_expected_hashrate(self) -> Optional[float]:
pass

View File

@@ -142,7 +142,7 @@ class BaseMiner(ABC):
@property
def model(self):
model_data = [self.raw_model]
model_data = [self.raw_model if self.raw_model is not None else "Unknown"]
if self.fw_str is not None:
model_data.append(f"({self.fw_str})")
return " ".join(model_data)

View File

@@ -26,6 +26,7 @@ class BaseWebAPI(ABC):
self.ip = ip # ipaddress.ip_address(ip)
self.username = "root"
self.pwd = "root"
self.port = 80
def __new__(cls, *args, **kwargs):
if cls is BaseWebAPI:

View File

@@ -35,10 +35,12 @@ class AntminerModernWebAPI(BaseWebAPI):
allow_warning: bool = True,
**parameters: Union[str, int, bool],
) -> dict:
url = f"http://{self.ip}/cgi-bin/{command}.cgi"
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:
async with httpx.AsyncClient(
transport=settings.transport(),
) as client:
if parameters:
data = await client.post(
url,
@@ -149,7 +151,7 @@ class AntminerOldWebAPI(BaseWebAPI):
allow_warning: bool = True,
**parameters: Union[str, int, bool],
) -> dict:
url = f"http://{self.ip}/cgi-bin/{command}.cgi"
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:

View File

@@ -31,6 +31,7 @@ class BOSMinerWebAPI(BaseWebAPI):
ip, settings.get("default_bosminer_password", "root")
)
self._pwd = settings.get("default_bosminer_password", "root")
self._port = 80
super().__init__(ip)
@property
@@ -42,6 +43,15 @@ class BOSMinerWebAPI(BaseWebAPI):
self._pwd = other
self.luci.pwd = other
@property
def port(self):
return self._port
@port.setter
def port(self, other: str):
self._port = other
self.luci.port = other
async def send_command(
self,
command: Union[str, dict],
@@ -63,6 +73,7 @@ class BOSerWebAPI(BOSMinerWebAPI):
ip, settings.get("default_bosminer_password", "root")
)
self.grpc = BOSerGRPCAPI(ip, settings.get("default_bosminer_password", "root"))
self._port = 80
super().__init__(ip)
@property
@@ -76,6 +87,16 @@ class BOSerWebAPI(BOSMinerWebAPI):
self.gql.pwd = other
self.grpc.pwd = other
@property
def port(self):
return self._port
@port.setter
def port(self, other: str):
self._port = other
self.luci.port = other
self.gql.port = other
async def send_command(
self,
command: Union[str, dict],
@@ -84,14 +105,14 @@ class BOSerWebAPI(BOSMinerWebAPI):
**parameters: Union[str, int, bool],
) -> dict:
command_type = self.select_command_type(command)
if command_type is "gql":
if command_type == "gql":
return await self.gql.send_command(command)
elif command_type is "grpc":
elif command_type == "grpc":
try:
return await (getattr(self.grpc, command.replace("grpc_", "")))()
except AttributeError:
raise APIError(f"No gRPC command found for command: {command}")
elif command_type is "luci":
elif command_type == "luci":
return await self.luci.send_command(command)
@staticmethod

View File

@@ -26,6 +26,7 @@ class BOSerGraphQLAPI:
self.ip = ip
self.username = "root"
self.pwd = pwd
self.port = 80
async def multicommand(self, *commands: dict) -> dict:
def merge(*d: dict):
@@ -60,7 +61,7 @@ class BOSerGraphQLAPI:
self,
command: dict,
) -> dict:
url = f"http://{self.ip}/graphql"
url = f"http://{self.ip}:{self.port}/graphql"
query = command
if command is None:
return {}
@@ -93,7 +94,7 @@ class BOSerGraphQLAPI:
return "{" + ",".join(data) + "}"
async def auth(self, client: httpx.AsyncClient) -> None:
url = f"http://{self.ip}/graphql"
url = f"http://{self.ip}:{self.port}/graphql"
await client.post(
url,
json={

View File

@@ -14,9 +14,11 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
import asyncio
import logging
from datetime import timedelta
from betterproto import Message
from grpclib import GRPCError, Status
from grpclib.client import Channel
from pyasic.errors import APIError
@@ -44,6 +46,7 @@ class BOSerGRPCAPI:
self.ip = ip
self.username = "root"
self.pwd = pwd
self.port = 50051
self._auth = None
self._auth_time = datetime.now()
@@ -90,13 +93,23 @@ class BOSerGRPCAPI:
metadata = []
if auth:
metadata.append(("authorization", await self.auth()))
async with Channel(self.ip, 50051) as c:
endpoint = getattr(BOSMinerGRPCStub(c), command)
if endpoint is None:
if not ignore_errors:
raise APIError(f"Command not found - {endpoint}")
return {}
return (await endpoint(message, metadata=metadata)).to_pydict()
try:
async with Channel(self.ip, self.port) as c:
endpoint = getattr(BOSMinerGRPCStub(c), command)
if endpoint is None:
if not ignore_errors:
raise APIError(f"Command not found - {endpoint}")
return {}
try:
return (await endpoint(message, metadata=metadata)).to_pydict()
except GRPCError as e:
if e.status == Status.UNAUTHENTICATED:
await self._get_auth()
metadata = [("authorization", await self.auth())]
return (await endpoint(message, metadata=metadata)).to_pydict()
raise e
except GRPCError as e:
raise APIError(f"gRPC command failed - {endpoint}") from e
async def auth(self):
if self._auth is not None and self._auth_time - datetime.now() < timedelta(
@@ -107,7 +120,7 @@ class BOSerGRPCAPI:
return self._auth
async def _get_auth(self):
async with Channel(self.ip, 50051) as c:
async with Channel(self.ip, self.port) as c:
req = LoginRequest(username=self.username, password=self.pwd)
async with c.request(
"/braiins.bos.v1.AuthenticationService/Login",
@@ -152,7 +165,9 @@ class BOSerGRPCAPI:
)
async def get_locate_device_status(self):
return await self.send_command("get_locate_device_status")
return await self.send_command(
"get_locate_device_status", GetLocateDeviceStatusRequest()
)
async def set_password(self, password: str = None):
return await self.send_command(
@@ -281,16 +296,72 @@ class BOSerGRPCAPI:
async def set_dps(
self,
enable: bool,
power_step: int,
min_power_target: int,
enable_shutdown: bool = None,
shutdown_duration: int = None,
):
raise NotImplementedError
return await self.send_command("braiins.bos.v1.PerformanceService/SetDPS")
async def set_performance_mode(self):
raise NotImplementedError
return await self.send_command(
"braiins.bos.v1.PerformanceService/SetPerformanceMode"
"set_dps",
message=SetDpsRequest(
enable=enable,
enable_shutdown=enable_shutdown,
shutdown_duration=shutdown_duration,
target=DpsTarget(
power_target=DpsPowerTarget(
power_step=Power(power_step),
min_power_target=Power(min_power_target),
)
),
),
)
async def set_performance_mode(
self,
wattage_target: int = None,
hashrate_target: int = None,
save_action: SaveAction = SaveAction.SAVE_ACTION_SAVE_AND_APPLY,
):
if wattage_target is not None and hashrate_target is not None:
logging.error(
"Cannot use both wattage_target and hashrate_target, using wattage_target."
)
elif wattage_target is None and hashrate_target is None:
raise APIError(
"No target supplied, please supply either wattage_target or hashrate_target."
)
if wattage_target is not None:
return await self.send_command(
"set_performance_mode",
message=SetPerformanceModeRequest(
save_action=save_action,
mode=PerformanceMode(
tuner_mode=TunerPerformanceMode(
power_target=PowerTargetMode(
power_target=Power(watt=wattage_target)
)
)
),
),
)
if hashrate_target is not None:
return await self.send_command(
"set_performance_mode",
message=SetPerformanceModeRequest(
save_action=save_action,
mode=PerformanceMode(
tuner_mode=TunerPerformanceMode(
hashrate_target=HashrateTargetMode(
hashrate_target=TeraHashrate(
terahash_per_second=hashrate_target
)
)
)
),
),
)
async def get_active_performance_mode(self):
return await self.send_command(
"get_active_performance_mode", GetPerformanceModeRequest()

View File

@@ -26,6 +26,7 @@ class BOSMinerLuCIAPI:
self.ip = ip
self.username = "root"
self.pwd = pwd
self.port = 80
async def multicommand(self, *commands: str) -> dict:
data = {}
@@ -38,7 +39,7 @@ class BOSMinerLuCIAPI:
async with httpx.AsyncClient(transport=settings.transport()) as client:
await self.auth(client)
data = await client.get(
f"http://{self.ip}/cgi-bin/luci/{path}",
f"http://{self.ip}:{self.port}/cgi-bin/luci/{path}",
headers={"User-Agent": "BTC Tools v0.1"},
)
if data.status_code == 200:
@@ -55,7 +56,7 @@ class BOSMinerLuCIAPI:
async def auth(self, session: httpx.AsyncClient):
login = {"luci_username": self.username, "luci_password": self.pwd}
url = f"http://{self.ip}/cgi-bin/luci"
url = f"http://{self.ip}:{self.port}/cgi-bin/luci"
headers = {
"User-Agent": "BTC Tools v0.1", # only seems to respond if this user-agent is set
"Content-Type": "application/x-www-form-urlencoded",

View File

@@ -29,6 +29,7 @@ class ePICWebAPI(BaseWebAPI):
self.username = "root"
self.pwd = settings.get("default_epic_password", "letmein")
self.token = None
self.port = 4028
async def send_command(
self,
@@ -50,13 +51,13 @@ class ePICWebAPI(BaseWebAPI):
"password": self.pwd,
}
response = await client.post(
f"http://{self.ip}:4028/{command}",
f"http://{self.ip}:{self.port}/{command}",
timeout=5,
json=epic_param,
)
else:
response = await client.get(
f"http://{self.ip}:4028/{command}",
f"http://{self.ip}:{self.port}/{command}",
timeout=5,
)
if not response.status_code == 200:

View File

@@ -33,10 +33,10 @@ class GoldshellWebAPI(BaseWebAPI):
async def auth(self):
async with httpx.AsyncClient(transport=settings.transport()) as client:
try:
await client.get(f"http://{self.ip}/user/logout")
await client.get(f"http://{self.ip}:{self.port}/user/logout")
auth = (
await client.get(
f"http://{self.ip}/user/login?username={self.username}&password={self.pwd}&cipher=false"
f"http://{self.ip}:{self.port}/user/login?username={self.username}&password={self.pwd}&cipher=false"
)
).json()
except httpx.HTTPError:
@@ -46,7 +46,7 @@ class GoldshellWebAPI(BaseWebAPI):
try:
auth = (
await client.get(
f"http://{self.ip}/user/login?username=admin&password=bbad7537f4c8b6ea31eea0b3d760e257&cipher=true"
f"http://{self.ip}:{self.port}/user/login?username=admin&password=bbad7537f4c8b6ea31eea0b3d760e257&cipher=true"
)
).json()
except (httpx.HTTPError, json.JSONDecodeError):
@@ -76,14 +76,14 @@ class GoldshellWebAPI(BaseWebAPI):
try:
if parameters:
response = await client.put(
f"http://{self.ip}/mcb/{command}",
f"http://{self.ip}:{self.port}/mcb/{command}",
headers={"Authorization": "Bearer " + self.jwt},
timeout=settings.get("api_function_timeout", 5),
json=parameters,
)
else:
response = await client.get(
f"http://{self.ip}/mcb/{command}",
f"http://{self.ip}:{self.port}/mcb/{command}",
headers={"Authorization": "Bearer " + self.jwt},
timeout=settings.get("api_function_timeout", 5),
)
@@ -106,7 +106,7 @@ class GoldshellWebAPI(BaseWebAPI):
for command in commands:
try:
response = await client.get(
f"http://{self.ip}/mcb/{command}",
f"http://{self.ip}:{self.port}/mcb/{command}",
headers={"Authorization": "Bearer " + self.jwt},
timeout=settings.get("api_function_timeout", 5),
)

View File

@@ -35,7 +35,7 @@ class InnosiliconWebAPI(BaseWebAPI):
async with httpx.AsyncClient(transport=settings.transport()) as client:
try:
auth = await client.post(
f"http://{self.ip}/api/auth",
f"http://{self.ip}:{self.port}/api/auth",
data={"username": self.username, "password": self.pwd},
)
except httpx.HTTPError:
@@ -58,7 +58,7 @@ class InnosiliconWebAPI(BaseWebAPI):
for i in range(settings.get("get_data_retries", 1)):
try:
response = await client.post(
f"http://{self.ip}/api/{command}",
f"http://{self.ip}:{self.port}/api/{command}",
headers={"Authorization": "Bearer " + self.jwt},
timeout=settings.get("api_function_timeout", 5),
json=parameters,
@@ -94,7 +94,7 @@ class InnosiliconWebAPI(BaseWebAPI):
for command in commands:
try:
response = await client.post(
f"http://{self.ip}/api/{command}",
f"http://{self.ip}:{self.port}/api/{command}",
headers={"Authorization": "Bearer " + self.jwt},
timeout=settings.get("api_function_timeout", 5),
)

View File

@@ -34,7 +34,7 @@ class VNishWebAPI(BaseWebAPI):
async with httpx.AsyncClient(transport=settings.transport()) as client:
try:
auth = await client.post(
f"http://{self.ip}/api/v1/unlock",
f"http://{self.ip}:{self.port}/api/v1/unlock",
json={"pw": self.pwd},
)
except httpx.HTTPError:
@@ -68,21 +68,21 @@ class VNishWebAPI(BaseWebAPI):
if parameters.get("post"):
parameters.pop("post")
response = await client.post(
f"http://{self.ip}/api/v1/{command}",
f"http://{self.ip}:{self.port}/api/v1/{command}",
headers={"Authorization": auth},
timeout=settings.get("api_function_timeout", 5),
json=parameters,
)
elif not parameters == {}:
response = await client.post(
f"http://{self.ip}/api/v1/{command}",
f"http://{self.ip}:{self.port}/api/v1/{command}",
headers={"Authorization": auth},
timeout=settings.get("api_function_timeout", 5),
json=parameters,
)
else:
response = await client.get(
f"http://{self.ip}/api/v1/{command}",
f"http://{self.ip}:{self.port}/api/v1/{command}",
headers={"Authorization": auth},
timeout=settings.get("api_function_timeout", 5),
)

View File

@@ -13,31 +13,27 @@
# See the License for the specific language governing permissions and -
# limitations under the License. -
# ------------------------------------------------------------------------------
import asyncio
import inspect
import sys
import unittest
import warnings
from dataclasses import asdict
from pyasic.miners.backends import CGMiner # noqa
from pyasic.miners.base import BaseMiner
from pyasic.miners.miner_factory import MINER_CLASSES, MinerFactory
from pyasic.miners.miner_factory import MINER_CLASSES
class MinersTest(unittest.TestCase):
def test_miner_model_creation(self):
def test_miner_type_creation(self):
warnings.filterwarnings("ignore")
for miner_model in MINER_CLASSES.keys():
for miner_api in MINER_CLASSES[miner_model].keys():
for miner_type in MINER_CLASSES.keys():
for miner_model in MINER_CLASSES[miner_type].keys():
with self.subTest(
msg=f"Creation of miner using model={miner_model}, api={miner_api}",
msg=f"Test creation of miner",
miner_type=miner_type,
miner_model=miner_model,
miner_api=miner_api,
):
miner = MINER_CLASSES[miner_model][miner_api]("127.0.0.1")
miner = MINER_CLASSES[miner_type][miner_model]("127.0.0.1")
self.assertTrue(
isinstance(miner, MINER_CLASSES[miner_model][miner_api])
isinstance(miner, MINER_CLASSES[miner_type][miner_model])
)
def test_miner_data_map_keys(self):
@@ -56,7 +52,6 @@ class MinersTest(unittest.TestCase):
"hostname",
"is_mining",
"mac",
"model",
"expected_hashrate",
"uptime",
"wattage",
@@ -64,14 +59,14 @@ class MinersTest(unittest.TestCase):
]
)
warnings.filterwarnings("ignore")
for miner_model in MINER_CLASSES.keys():
for miner_api in MINER_CLASSES[miner_model].keys():
for miner_type in MINER_CLASSES.keys():
for miner_model in MINER_CLASSES[miner_type].keys():
with self.subTest(
msg=f"Data map key check of miner using model={miner_model}, api={miner_api}",
msg=f"Data map key check",
miner_type=miner_type,
miner_model=miner_model,
miner_api=miner_api,
):
miner = MINER_CLASSES[miner_model][miner_api]("127.0.0.1")
miner = MINER_CLASSES[miner_type][miner_model]("127.0.0.1")
miner_keys = sorted(
[str(k) for k in asdict(miner.data_locations).keys()]
)
@@ -79,14 +74,14 @@ class MinersTest(unittest.TestCase):
def test_data_locations_match_signatures_command(self):
warnings.filterwarnings("ignore")
for miner_model in MINER_CLASSES.keys():
for miner_api in MINER_CLASSES[miner_model].keys():
miner = MINER_CLASSES[miner_model][miner_api]("127.0.0.1")
for miner_type in MINER_CLASSES.keys():
for miner_model in MINER_CLASSES[miner_type].keys():
miner = MINER_CLASSES[miner_type][miner_model]("127.0.0.1")
for data_point in asdict(miner.data_locations).values():
with self.subTest(
msg=f"Test {data_point['cmd']} signature matches with model={miner_model}, api={miner_api}",
msg=f"Test {data_point['cmd']} signature matches",
miner_type=miner_type,
miner_model=miner_model,
miner_api=miner_api,
):
func = getattr(miner, data_point["cmd"])
signature = inspect.signature(func)