update documentation and make BaseMiner and BaseMinerAPI unable to be instantiated directly. Add more unittests for miners.

This commit is contained in:
UpstreamData
2022-08-08 13:19:59 -06:00
parent 62238192ce
commit 8379359caf
24 changed files with 365 additions and 36 deletions

View File

@@ -15,11 +15,13 @@
import asyncssh
import logging
import ipaddress
from abc import ABC, abstractmethod
from pyasic.data import MinerData
from pyasic.config import MinerConfig
class BaseMiner:
class BaseMiner(ABC):
def __init__(self, *args) -> None:
self.ip = None
self.uname = "root"
@@ -34,6 +36,11 @@ class BaseMiner:
self.fan_count = 2
self.config = None
def __new__(cls, *args, **kwargs):
if cls is BaseMiner:
raise TypeError(f"Only children of '{cls.__name__}' may be instantiated")
return object.__new__(cls)
def __repr__(self):
return f"{'' if not self.api_type else self.api_type} {'' if not self.model else self.model}: {str(self.ip)}"
@@ -75,45 +82,56 @@ class BaseMiner:
except Exception as e:
raise e
@abstractmethod
async def fault_light_on(self) -> bool:
return False
pass
@abstractmethod
async def fault_light_off(self) -> bool:
return False
pass
async def send_file(self, src, dest):
async with (await self._get_ssh_connection()) as conn:
await asyncssh.scp(src, (conn, dest))
# async def send_file(self, src, dest):
# async with (await self._get_ssh_connection()) as conn:
# await asyncssh.scp(src, (conn, dest))
async def check_light(self):
return self.light
@abstractmethod
async def check_light(self) -> bool:
pass
# @abstractmethod
async def get_board_info(self):
return None
async def get_config(self):
return None
@abstractmethod
async def get_config(self) -> MinerConfig:
pass
async def get_hostname(self):
return None
@abstractmethod
async def get_hostname(self) -> str:
pass
async def get_model(self):
return None
@abstractmethod
async def get_model(self) -> str:
pass
async def reboot(self):
return False
@abstractmethod
async def reboot(self) -> bool:
pass
async def restart_backend(self):
return False
@abstractmethod
async def restart_backend(self) -> bool:
pass
async def send_config(self, *args, **kwargs):
return None
async def get_mac(self):
return None
@abstractmethod
async def get_mac(self) -> str:
pass
async def get_errors(self):
return None
@abstractmethod
async def get_errors(self) -> list:
pass
async def get_data(self) -> MinerData:
return MinerData(ip=str(self.ip))

View File

@@ -154,6 +154,26 @@ class BMMiner(BaseMiner):
return True
return False
async def check_light(self) -> bool:
if not self.light:
self.light = False
return self.light
async def fault_light_off(self) -> bool:
return False
async def fault_light_on(self) -> bool:
return False
async def get_errors(self) -> list:
return []
async def get_mac(self) -> str:
return "00:00:00:00:00:00"
async def restart_backend(self) -> bool:
return False
async def get_data(self) -> MinerData:
"""Get data from the miner.

View File

@@ -240,6 +240,49 @@ class BOSMiner(BaseMiner):
logging.debug(f"{self}: Restarting BOSMiner")
await conn.run("/etc/init.d/bosminer start")
async def check_light(self) -> bool:
if not self.light:
self.light = False
return self.light
async def get_errors(self) -> list:
tunerstatus = None
errors = []
try:
tunerstatus = await self.api.tunerstatus()
except Exception as e:
logging.warning(e)
if tunerstatus:
tuner = tunerstatus[0].get("TUNERSTATUS")
if tuner:
if len(tuner) > 0:
chain_status = tuner[0].get("TunerChainStatus")
if chain_status and len(chain_status) > 0:
board_map = {
0: "Left board",
1: "Center board",
2: "Right board",
}
offset = (
6
if chain_status[0]["HashchainIndex"] in [6, 7, 8]
else chain_status[0]["HashchainIndex"]
)
for board in chain_status:
_id = board["HashchainIndex"] - offset
if board["Status"] not in [
"Stable",
"Testing performance profile",
]:
_error = board["Status"]
_error = _error[0].lower() + _error[1:]
errors.append(
BraiinsOSError(f"{board_map[_id]} {_error}")
)
return errors
async def get_data(self) -> MinerData:
"""Get data from the miner.

View File

@@ -15,6 +15,7 @@
import logging
import ipaddress
from typing import Union
from pyasic.API.bosminer import BOSMinerAPI
from pyasic.miners import BaseMiner
@@ -29,7 +30,7 @@ class BOSMinerOld(BaseMiner):
self.uname = "root"
self.pwd = "admin"
async def send_ssh_command(self, cmd: str) -> str or None:
async def send_ssh_command(self, cmd: str) -> Union[str, None]:
"""Send a command to the miner over ssh.
:return: Result of the command or None.
@@ -61,3 +62,33 @@ class BOSMinerOld(BaseMiner):
async def update_to_plus(self):
result = await self.send_ssh_command("opkg update && opkg install bos_plus")
return result
async def check_light(self) -> bool:
return False
async def fault_light_on(self) -> bool:
return False
async def fault_light_off(self) -> bool:
return False
async def get_config(self) -> None:
return None
async def get_errors(self) -> list:
return []
async def get_hostname(self) -> str:
return "?"
async def get_mac(self) -> str:
return "00:00:00:00:00:00"
async def get_model(self) -> str:
return "S9"
async def reboot(self) -> bool:
return False
async def restart_backend(self) -> bool:
return False

View File

@@ -23,6 +23,7 @@ from pyasic.API import APIError
from pyasic.data import MinerData
from pyasic.data.error_codes import WhatsminerError
from pyasic.config import MinerConfig
from pyasic.settings import PyasicSettings
@@ -99,6 +100,40 @@ class BTMiner(BaseMiner):
return str(mac).upper()
async def check_light(self) -> bool:
if not self.light:
self.light = False
return self.light
async def fault_light_off(self) -> bool:
return False
async def fault_light_on(self) -> bool:
return False
async def get_errors(self) -> list:
return []
async def reboot(self) -> bool:
return False
async def restart_backend(self) -> bool:
return False
async def get_config(self) -> MinerConfig:
pools = None
cfg = MinerConfig()
try:
pools = await self.api.pools()
except APIError as e:
logging.warning(e)
if pools:
if "POOLS" in pools.keys():
cfg = cfg.from_api(pools["POOLS"])
return cfg
async def get_data(self) -> MinerData:
"""Get data from the miner.

View File

@@ -151,6 +151,23 @@ class CGMiner(BaseMiner):
self.config = result.stdout
return self.config
async def check_light(self) -> bool:
if not self.light:
self.light = False
return self.light
async def fault_light_off(self) -> bool:
return False
async def fault_light_on(self) -> bool:
return False
async def get_errors(self) -> list:
return []
async def get_mac(self) -> str:
return "00:00:00:00:00:00"
async def get_data(self) -> MinerData:
"""Get data from the miner.

View File

@@ -235,6 +235,7 @@ MINER_CLASSES = {
"Default": CGMinerAvalon1066,
"CGMiner": CGMinerAvalon1066,
},
"Unknown": {"Default": UnknownMiner},
}

View File

@@ -31,3 +31,29 @@ class UnknownMiner(BaseMiner):
async def get_hostname(self):
return "Unknown"
async def check_light(self) -> bool:
if not self.light:
self.light = False
return self.light
async def fault_light_off(self) -> bool:
return False
async def fault_light_on(self) -> bool:
return False
async def get_config(self) -> None:
return None
async def get_errors(self) -> list:
return []
async def get_mac(self) -> str:
return "00:00:00:00:00:00"
async def reboot(self) -> bool:
return False
async def restart_backend(self) -> bool:
return False