update documentation and make BaseMiner and BaseMinerAPI unable to be instantiated directly. Add more unittests for miners.
This commit is contained in:
@@ -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))
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -235,6 +235,7 @@ MINER_CLASSES = {
|
||||
"Default": CGMinerAvalon1066,
|
||||
"CGMiner": CGMinerAvalon1066,
|
||||
},
|
||||
"Unknown": {"Default": UnknownMiner},
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user