fixed more bugs with avalonminers
This commit is contained in:
@@ -62,7 +62,7 @@ class BaseMinerAPI:
|
|||||||
commands = [command for command in user_commands if command in allowed_commands]
|
commands = [command for command in user_commands if command in allowed_commands]
|
||||||
for item in list(set(user_commands) - set(commands)):
|
for item in list(set(user_commands) - set(commands)):
|
||||||
warnings.warn(f"""Removing incorrect command: {item}
|
warnings.warn(f"""Removing incorrect command: {item}
|
||||||
If you are sure you want to use this command please use API.send_command("{item}") instead.""",
|
If you are sure you want to use this command please use API.send_command("{item}", ignore_errors=True) instead.""",
|
||||||
APIWarning)
|
APIWarning)
|
||||||
# standard multicommand format is "command1+command2"
|
# standard multicommand format is "command1+command2"
|
||||||
# doesnt work for S19 which is dealt with in the send command function
|
# doesnt work for S19 which is dealt with in the send command function
|
||||||
@@ -84,7 +84,7 @@ If you are sure you want to use this command please use API.send_command("{item}
|
|||||||
if data:
|
if data:
|
||||||
return data
|
return data
|
||||||
|
|
||||||
async def send_command(self, command: str, parameters: str or int or bool = None) -> dict:
|
async def send_command(self, command: str, parameters: str or int or bool = None, ignore_errors: bool = False) -> dict:
|
||||||
"""Send an API command to the miner and return the result."""
|
"""Send an API command to the miner and return the result."""
|
||||||
try:
|
try:
|
||||||
# get reader and writer streams
|
# get reader and writer streams
|
||||||
@@ -123,10 +123,12 @@ If you are sure you want to use this command please use API.send_command("{item}
|
|||||||
writer.close()
|
writer.close()
|
||||||
await writer.wait_closed()
|
await writer.wait_closed()
|
||||||
|
|
||||||
# validate the command succeeded
|
# check for if the user wants to allow errors to return
|
||||||
validation = self.validate_command_output(data)
|
if not ignore_errors:
|
||||||
if not validation[0]:
|
# validate the command succeeded
|
||||||
raise APIError(validation[1])
|
validation = self.validate_command_output(data)
|
||||||
|
if not validation[0]:
|
||||||
|
raise APIError(validation[1])
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|||||||
@@ -267,49 +267,65 @@ async def scan_and_get_data(network):
|
|||||||
async def get_formatted_data(ip: ipaddress.ip_address):
|
async def get_formatted_data(ip: ipaddress.ip_address):
|
||||||
miner = await miner_factory.get_miner(ip)
|
miner = await miner_factory.get_miner(ip)
|
||||||
warnings.filterwarnings('ignore')
|
warnings.filterwarnings('ignore')
|
||||||
|
miner_data = None
|
||||||
|
host = await miner.get_hostname()
|
||||||
|
model = await miner.get_model()
|
||||||
|
if not model:
|
||||||
|
model = "Error"
|
||||||
|
temps = 0
|
||||||
|
th5s = 0
|
||||||
|
wattage = 0
|
||||||
|
user = "?"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
miner_data = await miner.api.multicommand("summary", "devs", "temps", "tunerstatus", "pools", "stats")
|
miner_data = await miner.api.multicommand("summary", "devs", "temps", "tunerstatus", "pools", "stats")
|
||||||
except APIError:
|
except APIError:
|
||||||
return {'TH/s': 0, 'IP': str(miner.ip), 'model': 'Unknown', 'temp': 0, 'host': 'Unknown', 'user': 'Unknown',
|
try:
|
||||||
'wattage': 0}
|
# no devs command, it will fail in this case
|
||||||
|
miner_data = await miner.api.multicommand("summary", "temps", "tunerstatus", "pools", "stats")
|
||||||
host = await miner.get_hostname()
|
print(miner_data)
|
||||||
model = await miner.get_model()
|
except APIError:
|
||||||
temps = 0
|
return {'TH/s': 0, 'IP': str(miner.ip), 'model': 'Unknown', 'temp': 0, 'host': 'Unknown', 'user': 'Unknown',
|
||||||
|
'wattage': 0}
|
||||||
if miner_data:
|
if miner_data:
|
||||||
|
# get all data from summary
|
||||||
if "summary" in miner_data.keys():
|
if "summary" in miner_data.keys():
|
||||||
if "Temperature" in miner_data['summary'][0]['SUMMARY'][0].keys():
|
if not miner_data["summary"][0].get("SUMMARY") == []:
|
||||||
if not round(miner_data['summary'][0]['SUMMARY'][0]["Temperature"]) == 0:
|
# temperature data, this is the idea spot to get this
|
||||||
temps = miner_data['summary'][0]['SUMMARY'][0]["Temperature"]
|
if "Temperature" in miner_data['summary'][0]['SUMMARY'][0].keys():
|
||||||
if 'MHS av' in miner_data['summary'][0]['SUMMARY'][0].keys():
|
if not round(miner_data['summary'][0]['SUMMARY'][0]["Temperature"]) == 0:
|
||||||
th5s = round(await safe_parse_api_data(miner_data, 'summary', 0, 'SUMMARY', 0, 'MHS av') / 1000000, 2)
|
temps = miner_data['summary'][0]['SUMMARY'][0]["Temperature"]
|
||||||
elif 'GHS av' in miner_data['summary'][0]['SUMMARY'][0].keys():
|
# hashrate data, this is the only place to get this for most miners as far as I know
|
||||||
if not miner_data['summary'][0]['SUMMARY'][0]['GHS av'] == "":
|
if 'MHS av' in miner_data['summary'][0]['SUMMARY'][0].keys():
|
||||||
th5s = round(
|
th5s = round(await safe_parse_api_data(miner_data, 'summary', 0, 'SUMMARY', 0, 'MHS av') / 1000000, 2)
|
||||||
float(await safe_parse_api_data(miner_data, 'summary', 0, 'SUMMARY', 0, 'GHS av')) / 1000,
|
elif 'GHS av' in miner_data['summary'][0]['SUMMARY'][0].keys():
|
||||||
2)
|
if not miner_data['summary'][0]['SUMMARY'][0]['GHS av'] == "":
|
||||||
else:
|
th5s = round(
|
||||||
th5s = 0
|
float(await safe_parse_api_data(miner_data, 'summary', 0, 'SUMMARY', 0, 'GHS av')) / 1000,
|
||||||
else:
|
2)
|
||||||
th5s = 0
|
|
||||||
else:
|
# alternate temperature data, for BraiinsOS
|
||||||
th5s = 0
|
if "temps" in miner_data.keys():
|
||||||
if "temps" in miner_data.keys() and not miner_data["temps"][0]['TEMPS'] == []:
|
if not miner_data["temps"][0]['TEMPS'] == []:
|
||||||
if "Chip" in miner_data["temps"][0]['TEMPS'][0].keys():
|
if "Chip" in miner_data["temps"][0]['TEMPS'][0].keys():
|
||||||
for board in miner_data["temps"][0]['TEMPS']:
|
for board in miner_data["temps"][0]['TEMPS']:
|
||||||
if board["Chip"] is not None and not board["Chip"] == 0.0:
|
if board["Chip"] is not None and not board["Chip"] == 0.0:
|
||||||
temps = board["Chip"]
|
temps = board["Chip"]
|
||||||
if "devs" in miner_data.keys() and not miner_data["devs"][0]['DEVS'] == []:
|
# alternate temperature data, for Whatsminers
|
||||||
if "Chip Temp Avg" in miner_data["devs"][0]['DEVS'][0].keys():
|
if "devs" in miner_data.keys():
|
||||||
for board in miner_data["devs"][0]['DEVS']:
|
if not miner_data["devs"][0].get('DEVS') == []:
|
||||||
if board['Chip Temp Avg'] is not None and not board['Chip Temp Avg'] == 0.0:
|
if "Chip Temp Avg" in miner_data["devs"][0]['DEVS'][0].keys():
|
||||||
temps = board['Chip Temp Avg']
|
for board in miner_data["devs"][0]['DEVS']:
|
||||||
if "stats" in miner_data.keys() and not miner_data["stats"][0]['STATS'] == []:
|
if board['Chip Temp Avg'] is not None and not board['Chip Temp Avg'] == 0.0:
|
||||||
for temp in ["temp2", "temp1", "temp3"]:
|
temps = board['Chip Temp Avg']
|
||||||
if temp in miner_data["stats"][0]['STATS'][1].keys():
|
# alternate temperature data
|
||||||
if miner_data["stats"][0]['STATS'][1][temp] is not None and not miner_data["stats"][0]['STATS'][1][
|
if "stats" in miner_data.keys():
|
||||||
temp] == 0.0:
|
if not miner_data["stats"][0]['STATS'] == []:
|
||||||
temps = miner_data["stats"][0]['STATS'][1][temp]
|
for temp in ["temp2", "temp1", "temp3"]:
|
||||||
|
if temp in miner_data["stats"][0]['STATS'][1].keys():
|
||||||
|
if miner_data["stats"][0]['STATS'][1][temp] is not None and not miner_data["stats"][0]['STATS'][1][temp] == 0.0:
|
||||||
|
temps = miner_data["stats"][0]['STATS'][1][temp]
|
||||||
|
# alternate temperature data, for Avalonminers
|
||||||
miner_data["stats"][0]['STATS'][0].keys()
|
miner_data["stats"][0]['STATS'][0].keys()
|
||||||
if any("MM ID" in string for string in miner_data["stats"][0]['STATS'][0].keys()):
|
if any("MM ID" in string for string in miner_data["stats"][0]['STATS'][0].keys()):
|
||||||
temp_all = []
|
temp_all = []
|
||||||
@@ -319,25 +335,20 @@ async def get_formatted_data(ip: ipaddress.ip_address):
|
|||||||
temp_all.append(int(value.split("[")[1].replace("]", "")))
|
temp_all.append(int(value.split("[")[1].replace("]", "")))
|
||||||
temps = round(sum(temp_all) / len(temp_all))
|
temps = round(sum(temp_all) / len(temp_all))
|
||||||
|
|
||||||
if "pools" not in miner_data.keys():
|
# pool information
|
||||||
user = "?"
|
if "pools" in miner_data.keys():
|
||||||
elif not miner_data['pools'][0]['POOLS'] == []:
|
if not miner_data['pools'][0].get('POOLS') == []:
|
||||||
user = await safe_parse_api_data(miner_data, 'pools', 0, 'POOLS', 0, 'User')
|
user = await safe_parse_api_data(miner_data, 'pools', 0, 'POOLS', 0, 'User')
|
||||||
else:
|
else:
|
||||||
user = "Blank"
|
print(miner_data['pools'][0])
|
||||||
|
user = "Blank"
|
||||||
|
|
||||||
|
# braiins tuner status / wattage
|
||||||
if "tunerstatus" in miner_data.keys():
|
if "tunerstatus" in miner_data.keys():
|
||||||
wattage = await safe_parse_api_data(miner_data, "tunerstatus", 0, 'TUNERSTATUS', 0, "PowerLimit")
|
wattage = await safe_parse_api_data(miner_data, "tunerstatus", 0, 'TUNERSTATUS', 0, "PowerLimit")
|
||||||
elif "Power" in miner_data["summary"][0]["SUMMARY"][0].keys():
|
elif "Power" in miner_data["summary"][0]["SUMMARY"][0].keys():
|
||||||
wattage = await safe_parse_api_data(miner_data, "summary", 0, 'SUMMARY', 0, "Power")
|
wattage = await safe_parse_api_data(miner_data, "summary", 0, 'SUMMARY', 0, "Power")
|
||||||
else:
|
|
||||||
wattage = 0
|
|
||||||
else:
|
|
||||||
th5s = 0
|
|
||||||
user = "Unknown"
|
|
||||||
wattage = 0
|
|
||||||
if not model:
|
|
||||||
model = "Error"
|
|
||||||
return {'TH/s': th5s, 'IP': str(miner.ip), 'model': model,
|
return {'TH/s': th5s, 'IP': str(miner.ip), 'model': model,
|
||||||
'temp': round(temps), 'host': host, 'user': user,
|
'temp': round(temps), 'host': host, 'user': user,
|
||||||
'wattage': wattage}
|
'wattage': wattage}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
from miners.bosminer import BOSminer
|
from miners.bosminer import BOSMiner
|
||||||
|
|
||||||
|
|
||||||
class BOSMinerS9(BOSminer):
|
class BOSMinerS9(BOSMiner):
|
||||||
def __init__(self, ip: str) -> None:
|
def __init__(self, ip: str) -> None:
|
||||||
super().__init__(ip)
|
super().__init__(ip)
|
||||||
self.model = "S9"
|
self.model = "S9"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
from miners.bosminer import BOSminer
|
from miners.bosminer import BOSMiner
|
||||||
|
|
||||||
|
|
||||||
class BOSMinerX17(BOSminer):
|
class BOSMinerX17(BOSMiner):
|
||||||
def __init__(self, ip: str) -> None:
|
def __init__(self, ip: str) -> None:
|
||||||
super().__init__(ip)
|
super().__init__(ip)
|
||||||
self.api_type = "BOSMiner"
|
self.api_type = "BOSMiner"
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import toml
|
|||||||
from config.bos import bos_config_convert, general_config_convert_bos
|
from config.bos import bos_config_convert, general_config_convert_bos
|
||||||
|
|
||||||
|
|
||||||
class BOSminer(BaseMiner):
|
class BOSMiner(BaseMiner):
|
||||||
def __init__(self, ip: str) -> None:
|
def __init__(self, ip: str) -> None:
|
||||||
api = BOSMinerAPI(ip)
|
api = BOSMinerAPI(ip)
|
||||||
super().__init__(ip, api)
|
super().__init__(ip, api)
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
from miners import BaseMiner
|
from miners import BaseMiner
|
||||||
from API.cgminer import CGMinerAPI
|
from API.cgminer import CGMinerAPI
|
||||||
|
from API import APIError
|
||||||
import asyncssh
|
import asyncssh
|
||||||
|
|
||||||
|
|
||||||
@@ -18,7 +19,10 @@ class CGMiner(BaseMiner):
|
|||||||
async def get_model(self):
|
async def get_model(self):
|
||||||
if self.model:
|
if self.model:
|
||||||
return self.model
|
return self.model
|
||||||
version_data = await self.api.devdetails()
|
try:
|
||||||
|
version_data = await self.api.devdetails()
|
||||||
|
except APIError:
|
||||||
|
return None
|
||||||
if version_data:
|
if version_data:
|
||||||
self.model = version_data["DEVDETAILS"][0]["Model"].replace("Antminer ", "")
|
self.model = version_data["DEVDETAILS"][0]["Model"].replace("Antminer ", "")
|
||||||
return self.model
|
return self.model
|
||||||
|
|||||||
@@ -17,7 +17,14 @@ from miners.whatsminer.M32 import BTMinerM32
|
|||||||
|
|
||||||
from miners.avalonminer import CGMinerAvalon
|
from miners.avalonminer import CGMinerAvalon
|
||||||
|
|
||||||
|
from miners.cgminer import CGMiner
|
||||||
|
from miners.bmminer import BMMiner
|
||||||
|
from miners.bosminer import BOSMiner
|
||||||
|
|
||||||
from miners.unknown import UnknownMiner
|
from miners.unknown import UnknownMiner
|
||||||
|
|
||||||
|
from API import APIError
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import ipaddress
|
import ipaddress
|
||||||
import json
|
import json
|
||||||
@@ -95,6 +102,14 @@ class MinerFactory:
|
|||||||
miner = BTMinerM31(str(ip))
|
miner = BTMinerM31(str(ip))
|
||||||
elif "M32" in model:
|
elif "M32" in model:
|
||||||
miner = BTMinerM32(str(ip))
|
miner = BTMinerM32(str(ip))
|
||||||
|
else:
|
||||||
|
if api:
|
||||||
|
if "BOSMiner" in api:
|
||||||
|
miner = BOSMiner(str(ip))
|
||||||
|
elif "CGMiner" in api:
|
||||||
|
miner = CGMiner(str(ip))
|
||||||
|
elif "BMMiner" in api:
|
||||||
|
miner = BMMiner(str(ip))
|
||||||
self.miners[ip] = miner
|
self.miners[ip] = miner
|
||||||
return miner
|
return miner
|
||||||
|
|
||||||
@@ -110,26 +125,26 @@ class MinerFactory:
|
|||||||
if data.get("STATUS"):
|
if data.get("STATUS"):
|
||||||
if not isinstance(data["STATUS"], str):
|
if not isinstance(data["STATUS"], str):
|
||||||
if data["STATUS"][0].get("STATUS") not in ["I", "S"]:
|
if data["STATUS"][0].get("STATUS") not in ["I", "S"]:
|
||||||
try:
|
data = await self._send_api_command(str(ip), "version")
|
||||||
data = await self._send_api_command(str(ip), "version")
|
if data:
|
||||||
model = data["VERSION"][0]["Type"]
|
if data.get("VERSION"):
|
||||||
except:
|
if data["VERSION"][0].get("Type"):
|
||||||
print(f"Get Model Exception: {ip}")
|
model = data["VERSION"][0]["Type"]
|
||||||
else:
|
else:
|
||||||
if not data["DEVDETAILS"][0]["Model"] == "":
|
if not data["DEVDETAILS"][0]["Model"] == "":
|
||||||
model = data["DEVDETAILS"][0]["Model"]
|
model = data["DEVDETAILS"][0]["Model"]
|
||||||
else:
|
else:
|
||||||
model = data["DEVDETAILS"][0]["Driver"]
|
model = data["DEVDETAILS"][0]["Driver"]
|
||||||
else:
|
else:
|
||||||
try:
|
data = await self._send_api_command(str(ip), "version")
|
||||||
data = await self._send_api_command(str(ip), "version")
|
model = data["VERSION"][0]["Type"]
|
||||||
model = data["VERSION"][0]["Type"]
|
|
||||||
except:
|
|
||||||
print(f"Get Model Exception: {ip}")
|
|
||||||
if model:
|
if model:
|
||||||
return model
|
return model
|
||||||
|
except APIError as e:
|
||||||
|
return None
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
if e.winerror == 121:
|
if e.winerror == 121:
|
||||||
|
print(e)
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
print(ip, e)
|
print(ip, e)
|
||||||
@@ -192,7 +207,6 @@ class MinerFactory:
|
|||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
async def _get_api_type(self, ip: ipaddress.ip_address or str) -> dict or None:
|
async def _get_api_type(self, ip: ipaddress.ip_address or str) -> dict or None:
|
||||||
"""Get data on the version of the miner to return the right miner."""
|
"""Get data on the version of the miner to return the right miner."""
|
||||||
api = None
|
api = None
|
||||||
|
|||||||
Reference in New Issue
Block a user