Compare commits

...

1 Commits

Author SHA1 Message Date
UpstreamData
841a546505 bug: fix some bugs. 2023-03-02 16:17:32 -07:00
10 changed files with 90 additions and 208 deletions

View File

@@ -291,7 +291,17 @@ class _PoolGroup:
Parameters:
user_suffix: The suffix to append to username.
"""
pools = {}
pools = {
"Pool1": None,
"UserName1": None,
"Password1": None,
"Pool2": None,
"UserName2": None,
"Password2": None,
"Pool3": None,
"UserName3": None,
"Password3": None,
}
for idx, pool in enumerate(self.pools[:3]):
pool_data = pool.as_inno(user_suffix=user_suffix)
for key in pool_data:
@@ -516,8 +526,14 @@ class MinerConfig:
for group in data["pool_groups"]:
pool_groups.append(_PoolGroup().from_dict(group))
for key in data:
if hasattr(self, key) and not key == "pool_groups":
if (
hasattr(self, key)
and not key == "pool_groups"
and not key == "miner_mode"
):
setattr(self, key, data[key])
if key == "miner_mode":
self.miner_mode = X19PowerMode(data[key])
self.pool_groups = pool_groups
return self

View File

@@ -19,8 +19,6 @@ import logging
from collections import namedtuple
from typing import List, Optional, Tuple
import asyncssh
from pyasic.API.cgminer import CGMinerAPI
from pyasic.config import MinerConfig
from pyasic.data import Fan, HashBoard
@@ -40,64 +38,6 @@ class CGMiner(BaseMiner):
self.pwd = "admin"
self.config = None
async def send_ssh_command(self, cmd: str) -> Optional[str]:
result = None
try:
conn = await self._get_ssh_connection()
except (asyncssh.Error, OSError):
return None
# open an ssh connection
async with conn:
# 3 retries
for i in range(3):
try:
# run the command and get the result
result = await conn.run(cmd)
result = result.stdout
except Exception as e:
# if the command fails, log it
logging.warning(f"{self} command {cmd} error: {e}")
# on the 3rd retry, return None
if i == 3:
return
continue
# return the result, either command output or None
return result
async def restart_backend(self) -> bool:
"""Restart cgminer hashing process. Wraps [`restart_cgminer`][pyasic.miners._backends.cgminer.CGMiner.restart_cgminer] to standardize."""
return await self.restart_cgminer()
async def restart_cgminer(self) -> bool:
"""Restart cgminer hashing process."""
commands = ["cgminer-api restart", "/usr/bin/cgminer-monitor >/dev/null 2>&1"]
commands = ";".join(commands)
try:
_ret = await self.send_ssh_command(commands)
except (asyncssh.Error, OSError):
return False
else:
if isinstance(_ret, str):
return True
return False
async def reboot(self) -> bool:
"""Reboots power to the physical miner."""
logging.debug(f"{self}: Sending reboot command.")
try:
_ret = await self.send_ssh_command("reboot")
except (asyncssh.Error, OSError):
return False
else:
logging.debug(f"{self}: Reboot command completed.")
if isinstance(_ret, str):
return True
return False
async def resume_mining(self) -> bool:
return False
@@ -199,15 +139,6 @@ class CGMiner(BaseMiner):
return self.fw_ver
async def get_hostname(self) -> Optional[str]:
try:
hn = await self.send_ssh_command("cat /proc/sys/kernel/hostname")
except (asyncssh.Error, OSError):
return None
if hn:
self.hostname = hn
return self.hostname
async def get_hashrate(self, api_summary: dict = None) -> Optional[float]:
# get hr from API
if not api_summary:

View File

@@ -37,16 +37,16 @@ class CGMinerA10X(CGMiner, A10X):
async def fault_light_off(self) -> bool:
return False
async def get_config(self, api_pools: dict = None) -> MinerConfig:
if not api_pools:
async def get_config(self, web_pools: dict = None) -> MinerConfig:
if not web_pools:
try:
api_pools = await self.api.pools()
web_pools = await self.web.pools()
except APIError as e:
logging.warning(e)
if api_pools:
if "POOLS" in api_pools.keys():
cfg = MinerConfig().from_api(api_pools["POOLS"])
if web_pools:
if "pools" in web_pools.keys():
cfg = MinerConfig().from_raw(web_pools)
self.config = cfg
return self.config
@@ -69,6 +69,12 @@ class CGMinerA10X(CGMiner, A10X):
async def restart_backend(self) -> bool:
return await self.restart_cgminer()
async def stop_mining(self) -> bool:
return False
async def resume_mining(self) -> bool:
return False
async def send_config(self, config: MinerConfig, user_suffix: str = None) -> None:
self.config = config
await self.web.update_pools(config.as_inno(user_suffix=user_suffix))

View File

@@ -33,13 +33,14 @@ class Goldshell(BFGMiner):
async def send_config(self, config: MinerConfig, user_suffix: str = None) -> None:
pools_data = await self.web.pools()
# have to delete all the pools one at a time first
for pool in pools_data:
await self.web.delpool(
url=pool["url"],
user=pool["user"],
password=pool["pass"],
dragid=pool["dragid"],
)
if pools_data:
for pool in pools_data:
await self.web.delpool(
url=pool["url"],
user=pool["user"],
password=pool["pass"],
dragid=pool["dragid"],
)
self.config = config

View File

@@ -33,13 +33,14 @@ class Goldshell(BFGMiner):
async def send_config(self, config: MinerConfig, user_suffix: str = None) -> None:
pools_data = await self.web.pools()
# have to delete all the pools one at a time first
for pool in pools_data:
await self.web.delpool(
url=pool["url"],
user=pool["user"],
password=pool["pass"],
dragid=pool["dragid"],
)
if pools_data:
for pool in pools_data:
await self.web.delpool(
url=pool["url"],
user=pool["user"],
password=pool["pass"],
dragid=pool["dragid"],
)
self.config = config

View File

@@ -160,16 +160,19 @@ class X7(BMMiner):
return False
async def stop_mining(self) -> bool:
cfg = await self.get_config()
cfg.miner_mode = X19PowerMode.Sleep
await self.send_config(cfg)
return True
return False
# maybe in a later update
# cfg = await self.get_config()
# cfg.miner_mode = X19PowerMode.Sleep
# await self.send_config(cfg)
# return True
async def resume_mining(self) -> bool:
cfg = await self.get_config()
cfg.miner_mode = X19PowerMode.Normal
await self.send_config(cfg)
return True
return False
# cfg = await self.get_config()
# cfg.miner_mode = X19PowerMode.Normal
# await self.send_config(cfg)
# return True
async def get_hostname(self) -> Union[str, None]:
try:

View File

@@ -949,22 +949,25 @@ class MinerFactory(metaclass=Singleton):
@staticmethod
async def __get_model_from_ssh(ip: ipaddress.ip_address) -> Union[str, None]:
model = None
async with asyncssh.connect(
str(ip),
known_hosts=None,
username="root",
password="admin",
server_host_key_algs=["ssh-rsa"],
) as conn:
board_name = None
cmd = await conn.run("cat /tmp/sysinfo/board_name")
if cmd:
board_name = cmd.stdout.strip()
if board_name == "am1-s9":
model = "ANTMINER S9"
if board_name == "am2-s17":
model = "ANTMINER S17"
return model
try:
async with asyncssh.connect(
str(ip),
known_hosts=None,
username="root",
password="admin",
server_host_key_algs=["ssh-rsa"],
) as conn:
board_name = None
cmd = await conn.run("cat /tmp/sysinfo/board_name")
if cmd:
board_name = cmd.stdout.strip()
if board_name == "am1-s9":
model = "ANTMINER S9"
if board_name == "am2-s17":
model = "ANTMINER S17"
return model
except ConnectionRefusedError:
return None
@staticmethod
async def __get_model_from_graphql(ip: ipaddress.ip_address) -> Union[str, None]:

View File

@@ -19,8 +19,6 @@ import logging
from collections import namedtuple
from typing import List, Optional, Tuple
import asyncssh
from pyasic.API.cgminer import CGMinerAPI
from pyasic.config import MinerConfig
from pyasic.data import Fan, HashBoard
@@ -40,93 +38,20 @@ class CGMiner(BaseMiner):
self.pwd = "admin"
self.config = None
async def send_ssh_command(self, cmd: str) -> Optional[str]:
result = None
try:
conn = await self._get_ssh_connection()
except (asyncssh.Error, OSError):
return None
# open an ssh connection
async with conn:
# 3 retries
for i in range(3):
try:
# run the command and get the result
result = await conn.run(cmd)
result = result.stdout
except Exception as e:
# if the command fails, log it
logging.warning(f"{self} command {cmd} error: {e}")
# on the 3rd retry, return None
if i == 3:
return
continue
# return the result, either command output or None
return result
async def restart_backend(self) -> bool:
"""Restart cgminer hashing process. Wraps [`restart_cgminer`][pyasic.miners._backends.cgminer.CGMiner.restart_cgminer] to standardize."""
return await self.restart_cgminer()
async def restart_cgminer(self) -> bool:
"""Restart cgminer hashing process."""
commands = ["cgminer-api restart", "/usr/bin/cgminer-monitor >/dev/null 2>&1"]
commands = ";".join(commands)
try:
_ret = await self.send_ssh_command(commands)
except (asyncssh.Error, OSError):
return False
else:
if isinstance(_ret, str):
return True
return False
async def get_hostname(self, *args, **kwargs) -> Optional[str]:
return None
async def reboot(self) -> bool:
"""Reboots power to the physical miner."""
logging.debug(f"{self}: Sending reboot command.")
try:
_ret = await self.send_ssh_command("reboot")
except (asyncssh.Error, OSError):
return False
else:
logging.debug(f"{self}: Reboot command completed.")
if isinstance(_ret, str):
return True
return False
async def stop_mining(self) -> bool:
return False
async def resume_mining(self) -> bool:
try:
commands = [
"mkdir -p /etc/tmp/",
'echo "*/3 * * * * /usr/bin/cgminer-monitor" > /etc/tmp/root',
"crontab -u root /etc/tmp/root",
"/usr/bin/cgminer-monitor >/dev/null 2>&1",
]
commands = ";".join(commands)
await self.send_ssh_command(commands)
except (asyncssh.Error, OSError):
return False
else:
return True
async def stop_mining(self) -> bool:
try:
commands = [
"mkdir -p /etc/tmp/",
'echo "" > /etc/tmp/root',
"crontab -u root /etc/tmp/root",
"killall cgminer",
]
commands = ";".join(commands)
await self.send_ssh_command(commands)
except (asyncssh.Error, OSError):
return False
else:
return True
return False
async def get_config(self) -> MinerConfig:
api_pools = await self.api.pools()
@@ -223,15 +148,6 @@ class CGMiner(BaseMiner):
return self.fw_ver
async def get_hostname(self) -> Optional[str]:
try:
hn = await self.send_ssh_command("cat /proc/sys/kernel/hostname")
except (asyncssh.Error, OSError):
return None
if hn:
self.hostname = hn
return self.hostname
async def get_hashrate(self, api_summary: dict = None) -> Optional[float]:
# get hr from API
if not api_summary:

View File

@@ -14,6 +14,7 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
import json
import urllib.parse
import warnings
from typing import Union
@@ -61,9 +62,10 @@ class InnosiliconWebAPI(BaseWebAPI):
f"http://{self.ip}/api/{command}",
headers={"Authorization": "Bearer " + self.jwt},
timeout=5,
data=parameters,
json=parameters,
)
json_data = response.json()
print(json_data)
if (
not json_data.get("success")
and "token" in json_data
@@ -104,3 +106,6 @@ class InnosiliconWebAPI(BaseWebAPI):
async def get_error_detail(self):
return await self.send_command("getErrorDetail")
async def pools(self):
return await self.send_command("pools")

View File

@@ -1,6 +1,6 @@
[tool.poetry]
name = "pyasic"
version = "0.32.0"
version = "0.32.1"
description = "A set of modules for interfacing with many common types of ASIC bitcoin miners, using both their API and SSH."
authors = ["UpstreamData <brett@upstreamdata.ca>"]
repository = "https://github.com/UpstreamData/pyasic"