Compare commits

...

27 Commits

Author SHA1 Message Date
UpstreamData
841a546505 bug: fix some bugs. 2023-03-02 16:17:32 -07:00
UpstreamData
e65b718699 version: bump version number. 2023-03-02 13:10:27 -07:00
UpstreamData
15e4338046 feature: add support for DR5, KD5, KDMax, CK5, and A10X. 2023-03-02 13:09:46 -07:00
UpstreamData
720d4aec3d feature: add support for Goldshell HS5 2023-03-02 11:32:28 -07:00
UpstreamData
09f9028ab5 format: reformat miner files to improve readability. 2023-03-02 08:58:10 -07:00
Upstream Data
25d971b699 version: bump version number. 2023-03-01 21:46:03 -07:00
Upstream Data
cd16ef3a25 feature: add Z15 support. 2023-03-01 21:45:37 -07:00
Upstream Data
b70010272f feature: add L7 support. 2023-03-01 20:32:03 -07:00
Upstream Data
140a457445 Merge branch 'dev' 2023-03-01 19:56:27 -07:00
Upstream Data
f4775e6311 bug: better fix for the issue with whatsminer pools. 2023-03-01 19:37:51 -07:00
Upstream Data
a4ecda93a2 bug: Fix an issue with sending None to whatsminers. 2023-03-01 19:34:14 -07:00
Arceris
ba90f2f082 Add VH40 and VH20 chip counts to M50.py 2023-03-01 18:56:41 -07:00
UpstreamData
44ac958bbb version: bump version number. 2023-02-28 16:23:36 -07:00
UpstreamData
e9bcf2ec9f bug: fix an issue with missing a check for bosminer config when getting data. 2023-02-28 16:23:04 -07:00
UpstreamData
c73dfad01a format: move vnish over to the new web API style. 2023-02-28 11:32:42 -07:00
UpstreamData
d222912e30 format: update a bunch of formatting and remove a lot of useless imports. 2023-02-28 09:35:11 -07:00
UpstreamData
6f1c1e0290 format: swap X9 and Innosilicon over to the new web api format. 2023-02-27 16:07:34 -07:00
UpstreamData
ba0bb73aa3 format: swap X17 over to the new web api format. 2023-02-27 15:44:58 -07:00
UpstreamData
13fcf1d4aa format: swap X19 over to the new web api format. 2023-02-27 15:32:02 -07:00
UpstreamData
6be1e94216 version: bump version number. 2023-02-24 12:32:22 -07:00
UpstreamData
709b3efa81 bug: fix mis-identification of X19 on some new versions of stock. 2023-02-24 12:31:55 -07:00
UpstreamData
5ac5770331 version: bump version number. 2023-02-24 08:58:11 -07:00
UpstreamData
f131ebbdf5 bug: fix miner mode needing to be parsed as an int not a str. 2023-02-24 08:57:28 -07:00
UpstreamData
5441e50f73 version: bump version number. 2023-02-24 08:49:29 -07:00
UpstreamData
dc6a952de4 bug: fix backwards modes for X19. 2023-02-24 08:49:13 -07:00
UpstreamData
b781d215fb version: bump version number. 2023-02-24 08:44:20 -07:00
UpstreamData
086b31ba23 feature: add enum for miner mode in config. 2023-02-24 08:43:52 -07:00
336 changed files with 6891 additions and 756 deletions

View File

@@ -92,7 +92,9 @@ class BaseMinerAPI:
async def send_privileged_command(self, *args, **kwargs) -> dict:
return await self.send_command(*args, **kwargs)
async def multicommand(self, *commands: str, allow_warning: bool = True) -> dict:
async def multicommand(
self, *commands: str, ignore_errors: bool = False, allow_warning: bool = True
) -> dict:
"""Creates and sends multiple commands as one command to the miner.
Parameters:
@@ -107,7 +109,9 @@ class BaseMinerAPI:
# standard format doesn't work for X19
command = "+".join(commands)
try:
data = await self.send_command(command, allow_warning=allow_warning)
data = await self.send_command(
command, allow_warning=allow_warning, ignore_errors=ignore_errors
)
except APIError:
return {command: [{}] for command in commands}
logging.debug(f"{self} - (Multicommand) - Received data")

673
pyasic/API/bfgminer.py Normal file
View File

@@ -0,0 +1,673 @@
# ------------------------------------------------------------------------------
# Copyright 2022 Upstream Data Inc -
# -
# Licensed under the Apache License, Version 2.0 (the "License"); -
# you may not use this file except in compliance with the License. -
# You may obtain a copy of the License at -
# -
# http://www.apache.org/licenses/LICENSE-2.0 -
# -
# Unless required by applicable law or agreed to in writing, software -
# distributed under the License is distributed on an "AS IS" BASIS, -
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -
# See the License for the specific language governing permissions and -
# limitations under the License. -
# ------------------------------------------------------------------------------
import logging
from pyasic.API import APIError, BaseMinerAPI
class BFGMinerAPI(BaseMinerAPI):
"""An abstraction of the BFGMiner API.
Each method corresponds to an API command in BFGMiner.
[BFGMiner API documentation](https://github.com/luke-jr/bfgminer/blob/bfgminer/README.RPC)
This class abstracts use of the BFGMiner API, as well as the
methods for sending commands to it. The self.send_command()
function handles sending a command to the miner asynchronously, and
as such is the base for many of the functions in this class, which
rely on it to send the command for them.
Parameters:
ip: The IP of the miner to reference the API on.
port: The port to reference the API on. Default is 4028.
"""
def __init__(self, ip: str, api_ver: str = "0.0.0", port: int = 4028):
super().__init__(ip, port)
self.api_ver = api_ver
async def multicommand(self, *commands: str, allow_warning: bool = True) -> dict:
# make sure we can actually run each command, otherwise they will fail
commands = self._check_commands(*commands)
# standard multicommand format is "command1+command2"
# doesn't work for S19 which uses the backup _x19_multicommand
command = "+".join(commands)
try:
data = await self.send_command(command, allow_warning=allow_warning)
except APIError:
logging.debug(f"{self} - (Multicommand) - Handling X19 multicommand.")
data = await self._x19_multicommand(*command.split("+"))
return data
async def _x19_multicommand(self, *commands):
data = None
try:
data = {}
# send all commands individually
for cmd in commands:
data[cmd] = []
data[cmd].append(await self.send_command(cmd, allow_warning=True))
except APIError:
pass
except Exception as e:
logging.warning(
f"{self} - ([Hidden] X19 Multicommand) - API Command Error {e}"
)
return data
async def version(self) -> dict:
"""Get miner version info.
<details>
<summary>Expand</summary>
Returns:
Miner version information.
</details>
"""
return await self.send_command("version")
async def config(self) -> dict:
"""Get some basic configuration info.
<details>
<summary>Expand</summary>
Returns:
## Some miner configuration information:
* ASC Count <- the number of ASCs
* PGA Count <- the number of PGAs
* Pool Count <- the number of Pools
* Strategy <- the current pool strategy
* Log Interval <- the interval of logging
* Device Code <- list of compiled device drivers
* OS <- the current operating system
* Failover-Only <- failover-only setting
* Scan Time <- scan-time setting
* Queue <- queue setting
* Expiry <- expiry setting
</details>
"""
return await self.send_command("config")
async def summary(self) -> dict:
"""Get the status summary of the miner.
<details>
<summary>Expand</summary>
Returns:
The status summary of the miner.
</details>
"""
return await self.send_command("summary")
async def pools(self) -> dict:
"""Get pool information.
<details>
<summary>Expand</summary>
Returns:
Miner pool information.
</details>
"""
return await self.send_command("pools")
async def devs(self) -> dict:
"""Get data on each PGA/ASC with their details.
<details>
<summary>Expand</summary>
Returns:
Data on each PGA/ASC with their details.
</details>
"""
return await self.send_command("devs")
async def procs(self) -> dict:
"""Get data on each processor with their details.
<details>
<summary>Expand</summary>
Returns:
Data on each processor with their details.
</details>
"""
return await self.send_command("procs")
async def devscan(self, info: str = "") -> dict:
"""Get data on each processor with their details.
<details>
<summary>Expand</summary>
Parameters:
info: Info to scan for device by.
Returns:
Data on each processor with their details.
</details>
"""
return await self.send_command("devscan", parameters=info)
async def pga(self, n: int) -> dict:
"""Get data from PGA n.
<details>
<summary>Expand</summary>
Parameters:
n: The PGA number to get data from.
Returns:
Data on the PGA n.
</details>
"""
return await self.send_command("pga", parameters=n)
async def proc(self, n: int = 0) -> dict:
"""Get data processor n.
<details>
<summary>Expand</summary>
Parameters:
n: The processor to get data on.
Returns:
Data on processor n.
</details>
"""
return await self.send_command("proc", parameters=n)
async def pgacount(self) -> dict:
"""Get data fon all PGAs.
<details>
<summary>Expand</summary>
Returns:
Data on the PGAs connected.
</details>
"""
return await self.send_command("pgacount")
async def proccount(self) -> dict:
"""Get data fon all processors.
<details>
<summary>Expand</summary>
Returns:
Data on the processors connected.
</details>
"""
return await self.send_command("proccount")
async def switchpool(self, n: int) -> dict:
"""Switch pools to pool n.
<details>
<summary>Expand</summary>
Parameters:
n: The pool to switch to.
Returns:
A confirmation of switching to pool n.
</details>
"""
return await self.send_command("switchpool", parameters=n)
async def enablepool(self, n: int) -> dict:
"""Enable pool n.
<details>
<summary>Expand</summary>
Parameters:
n: The pool to enable.
Returns:
A confirmation of enabling pool n.
</details>
"""
return await self.send_command("enablepool", parameters=n)
async def addpool(self, url: str, username: str, password: str) -> dict:
"""Add a pool to the miner.
<details>
<summary>Expand</summary>
Parameters:
url: The URL of the new pool to add.
username: The users username on the new pool.
password: The worker password on the new pool.
Returns:
A confirmation of adding the pool.
</details>
"""
return await self.send_command(
"addpool", parameters=f"{url},{username},{password}"
)
async def poolpriority(self, *n: int) -> dict:
"""Set pool priority.
<details>
<summary>Expand</summary>
Parameters:
*n: Pools in order of priority.
Returns:
A confirmation of setting pool priority.
</details>
"""
pools = f"{','.join([str(item) for item in n])}"
return await self.send_command("poolpriority", parameters=pools)
async def poolquota(self, n: int, q: int) -> dict:
"""Set pool quota.
<details>
<summary>Expand</summary>
Parameters:
n: Pool number to set quota on.
q: Quota to set the pool to.
Returns:
A confirmation of setting pool quota.
</details>
"""
return await self.send_command("poolquota", parameters=f"{n},{q}")
async def disablepool(self, n: int) -> dict:
"""Disable a pool.
<details>
<summary>Expand</summary>
Parameters:
n: Pool to disable.
Returns:
A confirmation of diabling the pool.
</details>
"""
return await self.send_command("disablepool", parameters=n)
async def removepool(self, n: int) -> dict:
"""Remove a pool.
<details>
<summary>Expand</summary>
Parameters:
n: Pool to remove.
Returns:
A confirmation of removing the pool.
</details>
"""
return await self.send_command("removepool", parameters=n)
async def save(self, filename: str = None) -> dict:
"""Save the config.
<details>
<summary>Expand</summary>
Parameters:
filename: Filename to save the config as.
Returns:
A confirmation of saving the config.
</details>
"""
if filename:
return await self.send_command("save", parameters=filename)
else:
return await self.send_command("save")
async def quit(self) -> dict:
"""Quit CGMiner.
<details>
<summary>Expand</summary>
Returns:
A single "BYE" before CGMiner quits.
</details>
"""
return await self.send_command("quit")
async def notify(self) -> dict:
"""Notify the user of past errors.
<details>
<summary>Expand</summary>
Returns:
The last status and count of each devices problem(s).
</details>
"""
return await self.send_command("notify")
async def privileged(self) -> dict:
"""Check if you have privileged access.
<details>
<summary>Expand</summary>
Returns:
The STATUS section with an error if you have no privileged access, or success if you have privileged access.
</details>
"""
return await self.send_command("privileged")
async def pgaenable(self, n: int) -> dict:
"""Enable PGA n.
<details>
<summary>Expand</summary>
Parameters:
n: The PGA to enable.
Returns:
A confirmation of enabling PGA n.
</details>
"""
return await self.send_command("pgaenable", parameters=n)
async def pgadisable(self, n: int) -> dict:
"""Disable PGA n.
<details>
<summary>Expand</summary>
Parameters:
n: The PGA to disable.
Returns:
A confirmation of disabling PGA n.
</details>
"""
return await self.send_command("pgadisable", parameters=n)
async def pgarestart(self, n: int) -> dict:
"""Restart PGA n.
<details>
<summary>Expand</summary>
Parameters:
n: The PGA to restart.
Returns:
A confirmation of restarting PGA n.
</details>
"""
return await self.send_command("pgadisable", parameters=n)
async def pgaidentify(self, n: int) -> dict:
"""Identify PGA n.
<details>
<summary>Expand</summary>
Parameters:
n: The PGA to identify.
Returns:
A confirmation of identifying PGA n.
</details>
"""
return await self.send_command("pgaidentify", parameters=n)
async def procenable(self, n: int) -> dict:
"""Enable processor n.
<details>
<summary>Expand</summary>
Parameters:
n: The processor to enable.
Returns:
A confirmation of enabling processor n.
</details>
"""
return await self.send_command("procenable", parameters=n)
async def procdisable(self, n: int) -> dict:
"""Disable processor n.
<details>
<summary>Expand</summary>
Parameters:
n: The processor to disable.
Returns:
A confirmation of disabling processor n.
</details>
"""
return await self.send_command("procdisable", parameters=n)
async def procrestart(self, n: int) -> dict:
"""Restart processor n.
<details>
<summary>Expand</summary>
Parameters:
n: The processor to restart.
Returns:
A confirmation of restarting processor n.
</details>
"""
return await self.send_command("procdisable", parameters=n)
async def procidentify(self, n: int) -> dict:
"""Identify processor n.
<details>
<summary>Expand</summary>
Parameters:
n: The processor to identify.
Returns:
A confirmation of identifying processor n.
</details>
"""
return await self.send_command("procidentify", parameters=n)
async def devdetails(self) -> dict:
"""Get data on all devices with their static details.
<details>
<summary>Expand</summary>
Returns:
Data on all devices with their static details.
</details>
"""
return await self.send_command("devdetails")
async def restart(self) -> dict:
"""Restart CGMiner using the API.
<details>
<summary>Expand</summary>
Returns:
A reply informing of the restart.
</details>
"""
return await self.send_command("restart")
async def stats(self) -> dict:
"""Get stats of each device/pool with more than 1 getwork.
<details>
<summary>Expand</summary>
Returns:
Stats of each device/pool with more than 1 getwork.
</details>
"""
return await self.send_command("stats")
async def check(self, command: str) -> dict:
"""Check if the command command exists in CGMiner.
<details>
<summary>Expand</summary>
Parameters:
command: The command to check.
Returns:
## Information about a command:
* Exists (Y/N) <- the command exists in this version
* Access (Y/N) <- you have access to use the command
</details>
"""
return await self.send_command("check", parameters=command)
async def failover_only(self, failover: bool) -> dict:
"""Set failover-only.
<details>
<summary>Expand</summary>
Parameters:
failover: What to set failover-only to.
Returns:
Confirmation of setting failover-only.
</details>
"""
return await self.send_command("failover-only", parameters=failover)
async def coin(self) -> dict:
"""Get information on the current coin.
<details>
<summary>Expand</summary>
Returns:
## Information about the current coin being mined:
* Hash Method <- the hashing algorithm
* Current Block Time <- blocktime as a float, 0 means none
* Current Block Hash <- the hash of the current block, blank means none
* LP <- whether LP is in use on at least 1 pool
* Network Difficulty: the current network difficulty
</details>
"""
return await self.send_command("coin")
async def debug(self, setting: str) -> dict:
"""Set a debug setting.
<details>
<summary>Expand</summary>
Parameters:
setting: Which setting to switch to.
## Options are:
* Silent
* Quiet
* Verbose
* Debug
* RPCProto
* PerDevice
* WorkTime
* Normal
Returns:
Data on which debug setting was enabled or disabled.
</details>
"""
return await self.send_command("debug", parameters=setting)
async def setconfig(self, name: str, n: int) -> dict:
"""Set config of name to value n.
<details>
<summary>Expand</summary>
Parameters:
name: The name of the config setting to set.
## Options are:
* queue
* scantime
* expiry
n: The value to set the 'name' setting to.
Returns:
The results of setting config of name to n.
</details>
"""
return await self.send_command("setconfig", parameters=f"{name},{n}")
async def pgaset(self, n: int, opt: str, val: int = None) -> dict:
"""Set PGA option opt to val on PGA n.
<details>
<summary>Expand</summary>
Options:
```
MMQ -
opt: clock
val: 2 - 250 (multiple of 2)
XBS -
opt: clock
val: 2 - 250 (multiple of 2)
```
Parameters:
n: The PGA to set the options on.
opt: The option to set. Setting this to 'help' returns a help message.
val: The value to set the option to.
Returns:
Confirmation of setting PGA n with opt[,val].
</details>
"""
if val:
return await self.send_command("pgaset", parameters=f"{n},{opt},{val}")
else:
return await self.send_command("pgaset", parameters=f"{n},{opt}")
async def pprocset(self, n: int, opt: str, val: int = None) -> dict:
"""Set processor option opt to val on processor n.
<details>
<summary>Expand</summary>
Options:
```
MMQ -
opt: clock
val: 2 - 250 (multiple of 2)
XBS -
opt: clock
val: 2 - 250 (multiple of 2)
```
Parameters:
n: The PGA to set the options on.
opt: The option to set. Setting this to 'help' returns a help message.
val: The value to set the option to.
Returns:
Confirmation of setting PGA n with opt[,val].
</details>
"""
if val:
return await self.send_command("pgaset", parameters=f"{n},{opt},{val}")
else:
return await self.send_command("pgaset", parameters=f"{n},{opt}")
async def zero(self, which: str, summary: bool) -> dict:
"""Zero a device.
<details>
<summary>Expand</summary>
Parameters:
which: Which device to zero. Setting this to 'all' zeros all devices. Setting this to 'bestshare' zeros only the bestshare values for each pool and global.
summary: Whether or not to show a full summary.
Returns:
the STATUS section with info on the zero and optional summary.
</details>
"""
return await self.send_command("zero", parameters=f"{which},{summary}")

View File

@@ -246,7 +246,7 @@ class BTMinerAPI(BaseMinerAPI):
logging.debug(f"{self} - (Send Privileged Command) - Sending")
try:
data = await self._send_bytes(enc_command, timeout)
except (asyncio.CancelledError, asyncio.TimeoutError) as e:
except (asyncio.CancelledError, asyncio.TimeoutError):
if ignore_errors:
return {}
raise APIError("No data was returned from the API.")

View File

@@ -62,7 +62,7 @@ class CGMinerAPI(BaseMinerAPI):
for cmd in commands:
data[cmd] = []
data[cmd].append(await self.send_command(cmd, allow_warning=True))
except APIError as e:
except APIError:
pass
except Exception as e:
logging.warning(

View File

@@ -14,18 +14,24 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
import json
import logging
import random
import string
import time
from dataclasses import asdict, dataclass, fields
from typing import Dict, List, Literal
from enum import IntEnum
from typing import List, Literal
import toml
import yaml
class X19PowerMode(IntEnum):
Normal = 0
Sleep = 1
LPM = 3
@dataclass
class _Pool:
"""A dataclass for pool information.
@@ -85,6 +91,45 @@ class _Pool:
pool = {"url": self.url, "user": username, "pass": self.password}
return pool
def as_x15(self, user_suffix: str = None) -> dict:
"""Convert the data in this class to a dict usable by an X15 device.
Parameters:
user_suffix: The suffix to append to username.
"""
username = self.username
if user_suffix:
username = f"{username}{user_suffix}"
pool = {"url": self.url, "user": username, "pass": self.password}
return pool
def as_x5(self, user_suffix: str = None) -> dict:
"""Convert the data in this class to a dict usable by an X5 device.
Parameters:
user_suffix: The suffix to append to username.
"""
username = self.username
if user_suffix:
username = f"{username}{user_suffix}"
pool = {"url": self.url, "user": username, "pass": self.password}
return pool
def as_goldshell(self, user_suffix: str = None) -> dict:
"""Convert the data in this class to a dict usable by a goldshell device.
Parameters:
user_suffix: The suffix to append to username.
"""
username = self.username
if user_suffix:
username = f"{username}{user_suffix}"
pool = {"url": self.url, "user": username, "pass": self.password}
return pool
def as_inno(self, user_suffix: str = None) -> dict:
"""Convert the data in this class to a dict usable by an Innosilicon device.
@@ -182,30 +227,104 @@ class _PoolGroup:
pools.append(pool.as_x19(user_suffix=user_suffix))
return pools
def as_x15(self, user_suffix: str = None) -> dict:
"""Convert the data in this class to a list usable by an X15 device.
Parameters:
user_suffix: The suffix to append to username.
"""
pools = {
"_ant_pool1url": "",
"_ant_pool1user": "",
"_ant_pool1pw": "",
"_ant_pool2url": "",
"_ant_pool2user": "",
"_ant_pool2pw": "",
"_ant_pool3url": "",
"_ant_pool3user": "",
"_ant_pool3pw": "",
}
for idx, pool in enumerate(self.pools[:3]):
pools[f"_ant_pool{idx+1}url"] = pool.as_x15(user_suffix=user_suffix)["url"]
pools[f"_ant_pool{idx+1}user"] = pool.as_x15(user_suffix=user_suffix)[
"user"
]
pools[f"_ant_pool{idx+1}pw"] = pool.as_x15(user_suffix=user_suffix)["pass"]
return pools
def as_x5(self, user_suffix: str = None) -> dict:
"""Convert the data in this class to a list usable by an X5 device.
Parameters:
user_suffix: The suffix to append to username.
"""
pools = {
"_ant_pool1url": "",
"_ant_pool1user": "",
"_ant_pool1pw": "",
"_ant_pool2url": "",
"_ant_pool2user": "",
"_ant_pool2pw": "",
"_ant_pool3url": "",
"_ant_pool3user": "",
"_ant_pool3pw": "",
}
for idx, pool in enumerate(self.pools[:3]):
pools[f"_ant_pool{idx+1}url"] = pool.as_x5(user_suffix=user_suffix)["url"]
pools[f"_ant_pool{idx+1}user"] = pool.as_x5(user_suffix=user_suffix)["user"]
pools[f"_ant_pool{idx+1}pw"] = pool.as_x5(user_suffix=user_suffix)["pass"]
return pools
def as_goldshell(self, user_suffix: str = None) -> list:
"""Convert the data in this class to a list usable by a goldshell device.
Parameters:
user_suffix: The suffix to append to username.
"""
return [pool.as_goldshell(user_suffix=user_suffix) for pool in self.pools[:3]]
def as_inno(self, user_suffix: str = None) -> dict:
"""Convert the data in this class to a list usable by an Innosilicon device.
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:
pools[f"{key}{idx+1}"] = pool_data[key]
return pools
def as_wm(self, user_suffix: str = None) -> List[dict]:
def as_wm(self, user_suffix: str = None) -> dict:
"""Convert the data in this class to a list usable by a Whatsminer device.
Parameters:
user_suffix: The suffix to append to username.
"""
pools = []
for pool in self.pools[:3]:
pools.append(pool.as_wm(user_suffix=user_suffix))
while len(pools) < 3:
pools.append({"url": None, "user": None, "pass": None})
pools = {}
for i in range(1, 4):
if i <= len(self.pools):
pool_wm = self.pools[i - 1].as_wm(user_suffix)
pools[f"pool_{i}"] = pool_wm["url"]
pools[f"worker_{i}"] = pool_wm["user"]
pools[f"passwd_{i}"] = pool_wm["pass"]
else:
pools[f"pool_{i}"] = ""
pools[f"worker_{i}"] = ""
pools[f"passwd_{i}"] = ""
return pools
def as_avalon(self, user_suffix: str = None) -> str:
@@ -267,6 +386,7 @@ class MinerConfig:
asicboost: bool = None
miner_mode: IntEnum = X19PowerMode.Normal
autotuning_enabled: bool = True
autotuning_mode: Literal["power", "hashrate"] = None
autotuning_wattage: int = None
@@ -287,6 +407,8 @@ class MinerConfig:
logging.debug(f"MinerConfig - (To Dict) - Dumping Dict config")
data_dict = asdict(self)
for key in asdict(self).keys():
if isinstance(data_dict[key], IntEnum):
data_dict[key] = data_dict[key].value
if data_dict[key] is None:
del data_dict[key]
return data_dict
@@ -310,6 +432,9 @@ class MinerConfig:
"""
logging.debug(f"MinerConfig - (From Raw) - Loading raw config")
pool_groups = []
if isinstance(data, list):
# goldshell config list
data = {"pools": data}
for key in data.keys():
if key == "pools":
pool_groups.append(_PoolGroup().from_dict({"pools": data[key]}))
@@ -324,10 +449,7 @@ class MinerConfig:
self.fan_speed = int(data["bitmain-fan-pwm"])
elif key == "bitmain-work-mode":
if data[key]:
if data[key] == 1:
self.autotuning_wattage = 0
if data[key] == 2:
self.autotuning_wattage = 1200
self.miner_mode = X19PowerMode(int(data[key]))
elif key == "fan_control":
for _key in data[key].keys():
if _key == "min_fans":
@@ -404,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
@@ -427,7 +555,7 @@ class MinerConfig:
logging.debug(f"MinerConfig - (From YAML) - Loading YAML config")
return self.from_dict(yaml.load(data, Loader=yaml.SafeLoader))
def as_wm(self, user_suffix: str = None) -> Dict[str, int]:
def as_wm(self, user_suffix: str = None) -> dict:
"""Convert the data in this class to a config usable by a Whatsminer device.
Parameters:
@@ -448,7 +576,7 @@ class MinerConfig:
logging.debug(f"MinerConfig - (As Inno) - Generating Innosilicon config")
return self.pool_groups[0].as_inno(user_suffix=user_suffix)
def as_x19(self, user_suffix: str = None) -> str:
def as_x19(self, user_suffix: str = None) -> dict:
"""Convert the data in this class to a config usable by an X19 device.
Parameters:
@@ -459,14 +587,8 @@ class MinerConfig:
"pools": self.pool_groups[0].as_x19(user_suffix=user_suffix),
"bitmain-fan-ctrl": False,
"bitmain-fan-pwn": 100,
"miner-mode": 0, # Normal Mode
"miner-mode": self.miner_mode.value,
}
if self.autotuning_wattage:
if self.autotuning_wattage == 0:
cfg["miner-mode"] = 1 # Sleep Mode
if self.autotuning_wattage < 1800:
cfg["miner-mode"] = 3 # LPM
if not self.temp_mode == "auto":
cfg["bitmain-fan-ctrl"] = True
@@ -474,7 +596,37 @@ class MinerConfig:
if self.fan_speed:
cfg["bitmain-fan-ctrl"] = str(self.fan_speed)
return json.dumps(cfg)
return cfg
def as_x15(self, user_suffix: str = None) -> dict:
"""Convert the data in this class to a config usable by an X15 device.
Parameters:
user_suffix: The suffix to append to username.
"""
cfg = self.pool_groups[0].as_x15(user_suffix=user_suffix)
return cfg
def as_x5(self, user_suffix: str = None) -> dict:
"""Convert the data in this class to a config usable by an X5 device.
Parameters:
user_suffix: The suffix to append to username.
"""
cfg = self.pool_groups[0].as_x5(user_suffix=user_suffix)
return cfg
def as_goldshell(self, user_suffix: str = None) -> list:
"""Convert the data in this class to a config usable by a goldshell device.
Parameters:
user_suffix: The suffix to append to username.
"""
cfg = self.pool_groups[0].as_goldshell(user_suffix=user_suffix)
return cfg
def as_avalon(self, user_suffix: str = None) -> str:
"""Convert the data in this class to a config usable by an Avalonminer device.

View File

@@ -429,7 +429,7 @@ class MinerData:
@property
def efficiency(self): # noqa - Skip PyCharm inspection
if self.hashrate == 0:
if self.hashrate == 0 or self.wattage == -1:
return 0
return round(self.wattage / self.hashrate)

View File

@@ -15,17 +15,25 @@
# ------------------------------------------------------------------------------
import asyncio
import logging
from typing import List, Union
# from pyasic.errors import PhaseBalancingError
from pyasic.errors import APIError
from pyasic.miners import AnyMiner
from pyasic.miners._backends import X19, BOSMiner, BTMiner
from pyasic.miners._types import S9, S17, T17, S17e, S17Plus, S17Pro, T17e, T17Plus
# from pprint import pprint as print
from pyasic.miners.btc._backends import ( # noqa - Ignore access to _module
X19,
BOSMiner,
BTMiner,
)
from pyasic.miners.btc._types import ( # noqa - Ignore access to _module
S9,
S17,
T17,
S17e,
S17Plus,
S17Pro,
T17e,
T17Plus,
)
FAN_USAGE = 50 # 50 W per fan

View File

@@ -31,9 +31,10 @@ from pyasic.errors import APIError
class BaseMiner(ABC):
def __init__(self, *args, **kwargs) -> None:
self.ip = None
self.uname = "root"
self.pwd = "admin"
self.api = None
self.web = None
self.uname = None
self.pwd = None
self.api_type = None
self.api_ver = None
self.fw_ver = None
@@ -396,8 +397,13 @@ class BaseMiner(ABC):
web_data = {}
for command in web_params:
data = await self.send_web_command(command) # noqa: web only anyway
web_data[command] = data
try:
cmd_func = getattr(self.web, command)
data = await cmd_func() # noqa: web only anyway
except (LookupError, APIError):
pass
else:
web_data[command] = data
for data_name in data_to_get:
function = getattr(self, "get_" + data_name)
sig = inspect.signature(function)

View File

@@ -0,0 +1,19 @@
# ------------------------------------------------------------------------------
# Copyright 2022 Upstream Data Inc -
# -
# Licensed under the Apache License, Version 2.0 (the "License"); -
# you may not use this file except in compliance with the License. -
# You may obtain a copy of the License at -
# -
# http://www.apache.org/licenses/LICENSE-2.0 -
# -
# Unless required by applicable law or agreed to in writing, software -
# distributed under the License is distributed on an "AS IS" BASIS, -
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -
# See the License for the specific language governing permissions and -
# limitations under the License. -
# ------------------------------------------------------------------------------
from .antminer import *
from .avalonminer import *
from .innosilicon import *
from .whatsminer import *

View File

@@ -15,47 +15,23 @@
# ------------------------------------------------------------------------------
import asyncio
import json
from typing import List, Optional, Union
import httpx
from pyasic.API import APIError
from pyasic.config import MinerConfig
from pyasic.config import MinerConfig, X19PowerMode
from pyasic.data.error_codes import MinerErrorData, X19Error
from pyasic.miners._backends import BMMiner # noqa - Ignore access to _module
from pyasic.settings import PyasicSettings
from pyasic.miners.btc._backends import BMMiner # noqa - Ignore access to _module
from pyasic.web.X19 import X19WebAPI
class X19(BMMiner):
def __init__(self, ip: str, api_ver: str = "0.0.0") -> None:
super().__init__(ip, api_ver=api_ver)
self.ip = ip
self.uname = "root"
self.pwd = PyasicSettings().global_x19_password
async def send_web_command(
self, command: str, params: dict = None
) -> Optional[dict]:
url = f"http://{self.ip}/cgi-bin/{command}.cgi"
auth = httpx.DigestAuth(self.uname, self.pwd)
try:
async with httpx.AsyncClient() as client:
if params:
data = await client.post(url, data=params, auth=auth)
else:
data = await client.get(url, auth=auth)
except httpx.HTTPError:
pass
else:
if data.status_code == 200:
try:
return data.json()
except json.decoder.JSONDecodeError:
pass
self.web = X19WebAPI(ip)
async def get_config(self) -> MinerConfig:
data = await self.send_web_command("get_miner_conf")
data = await self.web.get_miner_conf()
if data:
self.config = MinerConfig().from_raw(data)
return self.config
@@ -63,9 +39,7 @@ class X19(BMMiner):
async def send_config(self, config: MinerConfig, user_suffix: str = None) -> None:
self.config = config
conf = config.as_x19(user_suffix=user_suffix)
await self.send_web_command(
"set_miner_conf", params=conf # noqa: ignore conf being a str
)
await self.web.set_miner_conf(conf)
for i in range(7):
data = await self.get_config()
@@ -74,46 +48,40 @@ class X19(BMMiner):
await asyncio.sleep(1)
async def fault_light_on(self) -> bool:
data = await self.send_web_command(
"blink",
params=json.dumps({"blink": "true"}), # noqa - ignore params being a str
)
data = await self.web.blink(blink=True)
if data:
if data.get("code") == "B000":
self.light = True
return self.light
async def fault_light_off(self) -> bool:
data = await self.send_web_command(
"blink",
params=json.dumps({"blink": "false"}), # noqa - ignore params being a str
)
data = await self.web.blink(blink=False)
if data:
if data.get("code") == "B100":
self.light = True
return self.light
async def reboot(self) -> bool:
data = await self.send_web_command("reboot")
data = await self.web.reboot()
if data:
return True
return False
async def stop_mining(self) -> bool:
cfg = await self.get_config()
cfg.autotuning_wattage = 0
cfg.miner_mode = X19PowerMode.Sleep
await self.send_config(cfg)
return True
async def resume_mining(self) -> bool:
cfg = await self.get_config()
cfg.autotuning_wattage = 3600
cfg.miner_mode = X19PowerMode.Normal
await self.send_config(cfg)
return True
async def get_hostname(self) -> Union[str, None]:
try:
data = await self.send_web_command("get_system_info")
data = await self.web.get_system_info()
if data:
return data["hostname"]
except KeyError:
@@ -121,14 +89,14 @@ class X19(BMMiner):
async def get_mac(self) -> Union[str, None]:
try:
data = await self.send_web_command("get_system_info")
data = await self.web.get_system_info()
if data:
return data["macaddr"]
except KeyError:
pass
try:
data = await self.send_web_command("get_network_info")
data = await self.web.get_network_info()
if data:
return data["macaddr"]
except KeyError:
@@ -136,7 +104,7 @@ class X19(BMMiner):
async def get_errors(self) -> List[MinerErrorData]:
errors = []
data = await self.send_web_command("summary")
data = await self.web.summary()
if data:
try:
for item in data["SUMMARY"][0]["status"]:
@@ -153,7 +121,7 @@ class X19(BMMiner):
if self.light:
return self.light
try:
data = await self.send_web_command("get_blink_status")
data = await self.web.get_blink_status()
if data:
self.light = data["blink"]
except KeyError:
@@ -193,42 +161,34 @@ class X19(BMMiner):
):
if not hostname:
hostname = await self.get_hostname()
payload = {
"ipAddress": ip,
"ipDns": dns,
"ipGateway": gateway,
"ipHost": hostname,
"ipPro": 2, # static
"ipSub": subnet_mask,
}
await self.send_web_command("set_network_conf", params=payload)
await self.web.set_network_conf(
ip=ip,
dns=dns,
gateway=gateway,
subnet_mask=subnet_mask,
hostname=hostname,
protocol=2,
)
async def set_dhcp(self, hostname: str = None):
if not hostname:
hostname = await self.get_hostname()
payload = {
"ipAddress": "",
"ipDns": "",
"ipGateway": "",
"ipHost": hostname,
"ipPro": 1, # DHCP
"ipSub": "",
}
await self.send_web_command("set_network_conf", params=payload)
await self.web.set_network_conf(
ip="", dns="", gateway="", subnet_mask="", hostname=hostname, protocol=1
)
async def set_hostname(self, hostname: str):
cfg = await self.send_web_command("get_network_info")
cfg = await self.web.get_network_info()
dns = cfg["conf_dnsservers"]
gateway = cfg["conf_gateway"]
ip = cfg["conf_ipaddress"]
subnet_mask = cfg["conf_netmask"]
protocol = 1 if cfg["conf_nettype"] == "DHCP" else 2
payload = {
"ipAddress": ip,
"ipDns": dns,
"ipGateway": gateway,
"ipHost": hostname,
"ipPro": protocol,
"ipSub": subnet_mask,
}
await self.send_web_command("set_network_conf", params=payload)
await self.web.set_network_conf(
ip=ip,
dns=dns,
gateway=gateway,
subnet_mask=subnet_mask,
hostname=hostname,
protocol=protocol,
)

View File

@@ -17,17 +17,16 @@
import ipaddress
import logging
from collections import namedtuple
from typing import List, Optional, Tuple, Union
from typing import List, Optional, Tuple
import asyncssh
from pyasic.API.bmminer import BMMinerAPI
from pyasic.config import MinerConfig
from pyasic.data import Fan, HashBoard, MinerData
from pyasic.data import Fan, HashBoard
from pyasic.data.error_codes import MinerErrorData
from pyasic.errors import APIError
from pyasic.miners.base import BaseMiner
from pyasic.settings import PyasicSettings
class BMMiner(BaseMiner):

View File

@@ -26,11 +26,10 @@ import toml
from pyasic.API.bosminer import BOSMinerAPI
from pyasic.config import MinerConfig
from pyasic.data import Fan, HashBoard, MinerData
from pyasic.data import Fan, HashBoard
from pyasic.data.error_codes import BraiinsOSError, MinerErrorData
from pyasic.errors import APIError
from pyasic.miners.base import BaseMiner
from pyasic.settings import PyasicSettings
class BOSMiner(BaseMiner):
@@ -690,14 +689,15 @@ class BOSMiner(BaseMiner):
# need to use get_config, as this will never read perfectly as there are some bad edge cases
groups = []
cfg = await self.get_config()
for group in cfg.pool_groups:
pools = {"quota": group.quota}
for _i, _pool in enumerate(group.pools):
pools[f"pool_{_i + 1}_url"] = _pool.url.replace(
"stratum+tcp://", ""
).replace("stratum2+tcp://", "")
pools[f"pool_{_i + 1}_user"] = _pool.username
groups.append(pools)
if cfg:
for group in cfg.pool_groups:
pools = {"quota": group.quota}
for _i, _pool in enumerate(group.pools):
pools[f"pool_{_i + 1}_url"] = _pool.url.replace(
"stratum+tcp://", ""
).replace("stratum2+tcp://", "")
pools[f"pool_{_i + 1}_user"] = _pool.username
groups.append(pools)
return groups
else:
groups[0][f"pool_{i + 1}_url"] = (
@@ -839,7 +839,6 @@ class BOSMiner(BaseMiner):
api_devs = await self.api.devs()
except APIError:
pass
nom_hr = 0
if api_devs:
try:

View File

@@ -16,8 +16,7 @@
import ipaddress
import logging
from collections import namedtuple
from typing import List, Optional, Tuple, Union
from typing import List, Optional, Tuple
import asyncssh
@@ -180,5 +179,5 @@ class BOSMinerOld(BaseMiner):
async def get_nominal_hashrate(self) -> Optional[float]:
return None
async def get_data(self, allow_warning: bool = False) -> MinerData:
async def get_data(self, allow_warning: bool = False, **kwargs) -> MinerData:
return MinerData(ip=str(self.ip))

View File

@@ -18,15 +18,14 @@ import ipaddress
import logging
import warnings
from collections import namedtuple
from typing import List, Optional, Tuple, Union
from typing import List, Optional, Tuple
from pyasic.API.btminer import BTMinerAPI
from pyasic.config import MinerConfig
from pyasic.data import Fan, HashBoard, MinerData
from pyasic.data import Fan, HashBoard
from pyasic.data.error_codes import MinerErrorData, WhatsminerError
from pyasic.errors import APIError
from pyasic.miners.base import BaseMiner
from pyasic.settings import PyasicSettings
class BTMiner(BaseMiner):
@@ -122,17 +121,7 @@ class BTMiner(BaseMiner):
pools_conf = conf["pools"]
try:
await self.api.update_pools(
pools_conf[0]["url"],
pools_conf[0]["user"],
pools_conf[0]["pass"],
pools_conf[1]["url"],
pools_conf[1]["user"],
pools_conf[1]["pass"],
pools_conf[2]["url"],
pools_conf[2]["user"],
pools_conf[2]["pass"],
)
await self.api.update_pools(**pools_conf)
except APIError:
pass
try:
@@ -546,8 +535,6 @@ class BTMiner(BaseMiner):
pass
async def get_fault_light(self, api_get_miner_info: dict = None) -> bool:
data = None
if not api_get_miner_info:
try:
api_get_miner_info = await self.api.get_miner_info()

View File

@@ -17,17 +17,16 @@
import ipaddress
import logging
from collections import namedtuple
from typing import List, Optional, Tuple, Union
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, MinerData
from pyasic.data import Fan, HashBoard
from pyasic.data.error_codes import MinerErrorData
from pyasic.errors import APIError
from pyasic.miners.base import BaseMiner
from pyasic.settings import PyasicSettings
class CGMiner(BaseMiner):
@@ -129,12 +128,8 @@ class CGMiner(BaseMiner):
else:
return True
async def get_config(self, api_pools: dict = None) -> MinerConfig:
# get pool data
try:
api_pools = await self.api.pools()
except APIError:
pass
async def get_config(self) -> MinerConfig:
api_pools = await self.api.pools()
if api_pools:
self.config = MinerConfig().from_api(api_pools["POOLS"])

View File

@@ -14,20 +14,15 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
import ipaddress
import logging
import re
from collections import namedtuple
from typing import List, Optional, Tuple, Union
from typing import List, Optional
from pyasic.API.cgminer import CGMinerAPI
from pyasic.config import MinerConfig
from pyasic.data import Fan, HashBoard, MinerData
from pyasic.data import Fan, HashBoard
from pyasic.data.error_codes import MinerErrorData
from pyasic.errors import APIError
from pyasic.miners._backends import CGMiner
from pyasic.miners.base import BaseMiner
from pyasic.settings import PyasicSettings
from pyasic.miners.btc._backends import CGMiner
class CGMinerAvalon(CGMiner):
@@ -79,7 +74,7 @@ class CGMinerAvalon(CGMiner):
logging.debug(f"{self}: Sending config.") # noqa - This doesnt work...
conf = config.as_avalon(user_suffix=user_suffix)
try:
data = await self.api.ascset(
data = await self.api.ascset( # noqa
0, "setpool", f"root,root,{conf}"
) # this should work but doesn't
except APIError:

View File

@@ -16,7 +16,7 @@
import ipaddress
from pyasic.miners._backends import BMMiner
from pyasic.miners.btc._backends import BMMiner
class Hiveon(BMMiner):

View File

@@ -14,92 +14,19 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
import json
import logging
import warnings
from typing import Optional, Union
import httpx
from typing import Optional
from pyasic.errors import APIError
from pyasic.miners._backends.bmminer import BMMiner
from pyasic.settings import PyasicSettings
from pyasic.miners.btc._backends.bmminer import BMMiner
from pyasic.web.vnish import VNishWebAPI
class VNish(BMMiner):
def __init__(self, ip: str, api_ver: str = "0.0.0") -> None:
super().__init__(ip, api_ver)
self.api_type = "VNish"
self.uname = "root"
self.pwd = PyasicSettings().global_vnish_password
self.jwt = None
async def auth(self):
async with httpx.AsyncClient() as client:
try:
auth = await client.post(
f"http://{self.ip}/api/v1/unlock",
json={"pw": self.pwd},
)
except httpx.HTTPError:
warnings.warn(f"Could not authenticate web token with miner: {self}")
else:
if not auth.status_code == 200:
warnings.warn(
f"Could not authenticate web token with miner: {self}"
)
return None
json_auth = auth.json()
self.jwt = json_auth["token"]
return self.jwt
async def send_web_command(
self, command: str, data: Union[dict, None] = None, method: str = "GET"
):
if not self.jwt:
await self.auth()
if not data:
data = {}
async with httpx.AsyncClient() as client:
for i in range(PyasicSettings().miner_get_data_retries):
try:
auth = self.jwt
if command.startswith("system"):
auth = "Bearer " + self.jwt
if method == "GET":
response = await client.get(
f"http://{self.ip}/api/v1/{command}",
headers={"Authorization": auth},
timeout=5,
)
elif method == "POST":
if data:
response = await client.post(
f"http://{self.ip}/api/v1/{command}",
headers={"Authorization": auth},
timeout=5,
json=data,
)
else:
response = await client.post(
f"http://{self.ip}/api/v1/{command}",
headers={"Authorization": auth},
timeout=5,
)
else:
raise APIError("Bad method type.")
if not response.status_code == 200:
# refresh the token, retry
await self.auth()
continue
json_data = response.json()
if json_data:
return json_data
return True
except httpx.HTTPError:
pass
except json.JSONDecodeError:
pass
self.web = VNishWebAPI(ip)
async def get_model(self, api_stats: dict = None) -> Optional[str]:
# check if model is cached
@@ -122,16 +49,26 @@ class VNish(BMMiner):
pass
async def restart_backend(self) -> bool:
data = await self.send_web_command("mining/restart", method="POST")
return data
data = await self.web.restart_vnish()
if data:
try:
return data["success"]
except KeyError:
pass
return False
async def reboot(self) -> bool:
data = await self.send_web_command("system/reboot", method="POST")
return data
data = await self.web.reboot()
if data:
try:
return data["success"]
except KeyError:
pass
return False
async def get_mac(self, web_summary: dict = None) -> str:
if not web_summary:
web_info = await self.send_web_command("info")
web_info = await self.web.info()
if web_info:
try:
@@ -149,7 +86,7 @@ class VNish(BMMiner):
async def get_hostname(self, web_summary: dict = None) -> str:
if not web_summary:
web_info = await self.send_web_command("info")
web_info = await self.web.info()
if web_info:
try:
@@ -167,7 +104,7 @@ class VNish(BMMiner):
async def get_wattage(self, web_summary: dict = None) -> Optional[int]:
if not web_summary:
web_summary = await self.send_web_command("summary")
web_summary = await self.web.summary()
if web_summary:
try:
@@ -196,7 +133,7 @@ class VNish(BMMiner):
async def get_wattage_limit(self, web_settings: dict = None) -> Optional[int]:
if not web_settings:
web_settings = await self.send_web_command("summary")
web_settings = await self.web.summary()
if web_settings:
try:
@@ -207,7 +144,7 @@ class VNish(BMMiner):
async def get_fw_ver(self, web_summary: dict = None) -> Optional[str]:
if not web_summary:
web_summary = await self.send_web_command("summary")
web_summary = await self.web.summary()
if web_summary:
try:

View File

@@ -14,7 +14,7 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
from pyasic.miners._types.makes import AntMiner
from pyasic.miners.makes import AntMiner
class S17(AntMiner): # noqa - ignore ABC method implementation

View File

@@ -14,7 +14,7 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
from pyasic.miners._types.makes import AntMiner
from pyasic.miners.makes import AntMiner
class S17Plus(AntMiner): # noqa - ignore ABC method implementation

View File

@@ -14,7 +14,7 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
from pyasic.miners._types.makes import AntMiner
from pyasic.miners.makes import AntMiner
class S17Pro(AntMiner): # noqa - ignore ABC method implementation

View File

@@ -14,7 +14,7 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
from pyasic.miners._types.makes import AntMiner
from pyasic.miners.makes import AntMiner
class S17e(AntMiner): # noqa - ignore ABC method implementation

View File

@@ -14,7 +14,7 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
from pyasic.miners._types.makes import AntMiner
from pyasic.miners.makes import AntMiner
class T17(AntMiner): # noqa - ignore ABC method implementation

View File

@@ -14,7 +14,7 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
from pyasic.miners._types.makes import AntMiner
from pyasic.miners.makes import AntMiner
class T17Plus(AntMiner): # noqa - ignore ABC method implementation

View File

@@ -14,7 +14,7 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
from pyasic.miners._types.makes import AntMiner
from pyasic.miners.makes import AntMiner
class T17e(AntMiner): # noqa - ignore ABC method implementation

View File

@@ -14,7 +14,7 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
from pyasic.miners._types.makes import AntMiner
from pyasic.miners.makes import AntMiner
class S19(AntMiner): # noqa - ignore ABC method implementation

View File

@@ -14,7 +14,7 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
from pyasic.miners._types.makes import AntMiner
from pyasic.miners.makes import AntMiner
class S19Pro(AntMiner): # noqa - ignore ABC method implementation

View File

@@ -14,7 +14,7 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
from pyasic.miners._types.makes import AntMiner
from pyasic.miners.makes import AntMiner
class S19XP(AntMiner): # noqa - ignore ABC method implementation

View File

@@ -14,7 +14,7 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
from pyasic.miners._types.makes import AntMiner
from pyasic.miners.makes import AntMiner
class S19a(AntMiner): # noqa - ignore ABC method implementation

View File

@@ -14,7 +14,7 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
from pyasic.miners._types.makes import AntMiner
from pyasic.miners.makes import AntMiner
class S19aPro(AntMiner): # noqa - ignore ABC method implementation

View File

@@ -14,7 +14,7 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
from pyasic.miners._types.makes import AntMiner
from pyasic.miners.makes import AntMiner
class S19j(AntMiner): # noqa - ignore ABC method implementation

View File

@@ -14,7 +14,7 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
from pyasic.miners._types.makes import AntMiner
from pyasic.miners.makes import AntMiner
class S19jPro(AntMiner): # noqa - ignore ABC method implementation

View File

@@ -14,7 +14,7 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
from pyasic.miners._types.makes import AntMiner
from pyasic.miners.makes import AntMiner
class T19(AntMiner): # noqa - ignore ABC method implementation

View File

@@ -14,7 +14,7 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
from pyasic.miners._types.makes import AntMiner
from pyasic.miners.makes import AntMiner
class S9(AntMiner): # noqa - ignore ABC method implementation

View File

@@ -14,7 +14,7 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
from pyasic.miners._types.makes import AntMiner
from pyasic.miners.makes import AntMiner
class S9i(AntMiner): # noqa - ignore ABC method implementation

View File

@@ -14,7 +14,7 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
from pyasic.miners._types.makes import AntMiner
from pyasic.miners.makes import AntMiner
class T9(AntMiner): # noqa - ignore ABC method implementation

View File

@@ -13,7 +13,6 @@
# See the License for the specific language governing permissions and -
# limitations under the License. -
# ------------------------------------------------------------------------------
from .X9 import *
from .X17 import *
from .X19 import *

View File

@@ -14,7 +14,7 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
from pyasic.miners._types.makes import AvalonMiner
from pyasic.miners.makes import AvalonMiner
class Avalon1026(AvalonMiner): # noqa - ignore ABC method implementation

View File

@@ -14,7 +14,7 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
from pyasic.miners._types.makes import AvalonMiner
from pyasic.miners.makes import AvalonMiner
class Avalon1047(AvalonMiner): # noqa - ignore ABC method implementation

View File

@@ -14,7 +14,7 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
from pyasic.miners._types.makes import AvalonMiner
from pyasic.miners.makes import AvalonMiner
class Avalon1066(AvalonMiner): # noqa - ignore ABC method implementation

View File

@@ -14,7 +14,7 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
from pyasic.miners._types.makes import AvalonMiner
from pyasic.miners.makes import AvalonMiner
class Avalon721(AvalonMiner): # noqa - ignore ABC method implementation

View File

@@ -14,7 +14,7 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
from pyasic.miners._types.makes import AvalonMiner
from pyasic.miners.makes import AvalonMiner
class Avalon741(AvalonMiner): # noqa - ignore ABC method implementation

View File

@@ -14,7 +14,7 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
from pyasic.miners._types.makes import AvalonMiner
from pyasic.miners.makes import AvalonMiner
class Avalon761(AvalonMiner): # noqa - ignore ABC method implementation

View File

@@ -14,7 +14,7 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
from pyasic.miners._types.makes import AvalonMiner
from pyasic.miners.makes import AvalonMiner
class Avalon821(AvalonMiner): # noqa - ignore ABC method implementation

View File

@@ -14,7 +14,7 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
from pyasic.miners._types.makes import AvalonMiner
from pyasic.miners.makes import AvalonMiner
class Avalon841(AvalonMiner): # noqa - ignore ABC method implementation

View File

@@ -14,7 +14,7 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
from pyasic.miners._types.makes import AvalonMiner
from pyasic.miners.makes import AvalonMiner
class Avalon851(AvalonMiner): # noqa - ignore ABC method implementation

View File

@@ -14,7 +14,7 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
from pyasic.miners._types.makes import AvalonMiner
from pyasic.miners.makes import AvalonMiner
class Avalon921(AvalonMiner): # noqa - ignore ABC method implementation

View File

@@ -14,7 +14,7 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
from pyasic.miners._types.makes import InnosiliconMiner
from pyasic.miners.makes import InnosiliconMiner
class InnosiliconT3HPlus(InnosiliconMiner): # noqa - ignore ABC method implementation

View File

@@ -14,7 +14,7 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
from pyasic.miners._types.makes import WhatsMiner
from pyasic.miners.makes import WhatsMiner
class M20V10(WhatsMiner): # noqa - ignore ABC method implementation

View File

@@ -16,7 +16,7 @@
import warnings
from pyasic.miners._types.makes import WhatsMiner
from pyasic.miners.makes import WhatsMiner
class M20SV10(WhatsMiner): # noqa - ignore ABC method implementation

View File

@@ -16,7 +16,7 @@
import warnings
from pyasic.miners._types.makes import WhatsMiner
from pyasic.miners.makes import WhatsMiner
class M20SPlusV30(WhatsMiner): # noqa - ignore ABC method implementation

View File

@@ -16,7 +16,7 @@
import warnings
from pyasic.miners._types.makes import WhatsMiner
from pyasic.miners.makes import WhatsMiner
class M21V10(WhatsMiner): # noqa - ignore ABC method implementation

View File

@@ -16,7 +16,7 @@
import warnings
from pyasic.miners._types.makes import WhatsMiner
from pyasic.miners.makes import WhatsMiner
class M21SV20(WhatsMiner): # noqa - ignore ABC method implementation

View File

@@ -16,7 +16,7 @@
import warnings
from pyasic.miners._types.makes import WhatsMiner
from pyasic.miners.makes import WhatsMiner
class M21SPlusV20(WhatsMiner): # noqa - ignore ABC method implementation

View File

@@ -16,7 +16,7 @@
import warnings
from pyasic.miners._types.makes import WhatsMiner
from pyasic.miners.makes import WhatsMiner
class M29V10(WhatsMiner): # noqa - ignore ABC method implementation

View File

@@ -16,7 +16,7 @@
import warnings
from pyasic.miners._types.makes import WhatsMiner
from pyasic.miners.makes import WhatsMiner
class M30V10(WhatsMiner): # noqa - ignore ABC method implementation

View File

@@ -16,7 +16,7 @@
import warnings
from pyasic.miners._types.makes import WhatsMiner
from pyasic.miners.makes import WhatsMiner
class M30SV10(WhatsMiner): # noqa - ignore ABC method implementation

View File

@@ -16,7 +16,7 @@
import warnings
from pyasic.miners._types.makes import WhatsMiner
from pyasic.miners.makes import WhatsMiner
class M30SPlusV10(WhatsMiner): # noqa - ignore ABC method implementation

View File

@@ -16,7 +16,7 @@
import warnings
from pyasic.miners._types.makes import WhatsMiner
from pyasic.miners.makes import WhatsMiner
class M30SPlusPlusV10(WhatsMiner): # noqa - ignore ABC method implementation

View File

@@ -16,7 +16,7 @@
import warnings
from pyasic.miners._types.makes import WhatsMiner
from pyasic.miners.makes import WhatsMiner
class M31V10(WhatsMiner): # noqa - ignore ABC method implementation

View File

@@ -16,7 +16,7 @@
import warnings
from pyasic.miners._types.makes import WhatsMiner
from pyasic.miners.makes import WhatsMiner
class M31HV40(WhatsMiner): # noqa - ignore ABC method implementation

View File

@@ -16,7 +16,7 @@
import warnings
from pyasic.miners._types.makes import WhatsMiner
from pyasic.miners.makes import WhatsMiner
class M31SV10(WhatsMiner): # noqa - ignore ABC method implementation

View File

@@ -16,7 +16,7 @@
import warnings
from pyasic.miners._types.makes import WhatsMiner
from pyasic.miners.makes import WhatsMiner
class M31SEV10(WhatsMiner): # noqa - ignore ABC method implementation

View File

@@ -16,7 +16,7 @@
import warnings
from pyasic.miners._types.makes import WhatsMiner
from pyasic.miners.makes import WhatsMiner
class M31SPlusV10(WhatsMiner): # noqa - ignore ABC method implementation

View File

@@ -16,7 +16,7 @@
import warnings
from pyasic.miners._types.makes import WhatsMiner
from pyasic.miners.makes import WhatsMiner
class M32V10(WhatsMiner): # noqa - ignore ABC method implementation

View File

@@ -14,7 +14,7 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
from pyasic.miners._types.makes import WhatsMiner
from pyasic.miners.makes import WhatsMiner
class M32S(WhatsMiner): # noqa - ignore ABC method implementation

View File

@@ -16,7 +16,7 @@
import warnings
from pyasic.miners._types.makes import WhatsMiner
from pyasic.miners.makes import WhatsMiner
class M33V10(WhatsMiner): # noqa - ignore ABC method implementation

View File

@@ -16,7 +16,7 @@
import warnings
from pyasic.miners._types.makes import WhatsMiner
from pyasic.miners.makes import WhatsMiner
class M33SVG30(WhatsMiner): # noqa - ignore ABC method implementation

View File

@@ -16,7 +16,7 @@
import warnings
from pyasic.miners._types.makes import WhatsMiner
from pyasic.miners.makes import WhatsMiner
class M33SPlusVH20(WhatsMiner): # noqa - ignore ABC method implementation

View File

@@ -16,7 +16,7 @@
import warnings
from pyasic.miners._types.makes import WhatsMiner
from pyasic.miners.makes import WhatsMiner
class M33SPlusPlusVH20(WhatsMiner): # noqa - ignore ABC method implementation

View File

@@ -14,7 +14,7 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
from pyasic.miners._types.makes import WhatsMiner
from pyasic.miners.makes import WhatsMiner
class M34SPlusVE10(WhatsMiner): # noqa - ignore ABC method implementation

View File

@@ -16,7 +16,7 @@
import warnings
from pyasic.miners._types.makes import WhatsMiner
from pyasic.miners.makes import WhatsMiner
class M36SVE10(WhatsMiner): # noqa - ignore ABC method implementation

View File

@@ -16,7 +16,7 @@
import warnings
from pyasic.miners._types.makes import WhatsMiner
from pyasic.miners.makes import WhatsMiner
class M36SPlusVG30(WhatsMiner): # noqa - ignore ABC method implementation

View File

@@ -16,7 +16,7 @@
import warnings
from pyasic.miners._types.makes import WhatsMiner
from pyasic.miners.makes import WhatsMiner
class M36SPlusPlusVH30(WhatsMiner): # noqa - ignore ABC method implementation

View File

@@ -16,7 +16,7 @@
import warnings
from pyasic.miners._types.makes import WhatsMiner
from pyasic.miners.makes import WhatsMiner
class M39V20(WhatsMiner): # noqa - ignore ABC method implementation

View File

@@ -16,7 +16,7 @@
import warnings
from pyasic.miners._types.makes import WhatsMiner
from pyasic.miners.makes import WhatsMiner
class M50VG30(WhatsMiner): # noqa - ignore ABC method implementation
@@ -48,10 +48,7 @@ class M50VH20(WhatsMiner): # noqa - ignore ABC method implementation
super().__init__()
self.ip = ip
self.model = "M50 VH20"
self.nominal_chips = 0
warnings.warn(
"Unknown chip count for miner type M50 VH20, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
)
self.nominal_chips = 111
self.fan_count = 2
@@ -72,10 +69,7 @@ class M50VH40(WhatsMiner): # noqa - ignore ABC method implementation
super().__init__()
self.ip = ip
self.model = "M50 VH40"
self.nominal_chips = 0
warnings.warn(
"Unknown chip count for miner type M50 VH40, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
)
self.nominal_chips = 84
self.fan_count = 2

View File

@@ -16,7 +16,7 @@
import warnings
from pyasic.miners._types.makes import WhatsMiner
from pyasic.miners.makes import WhatsMiner
class M50SVJ10(WhatsMiner): # noqa - ignore ABC method implementation

View File

@@ -16,7 +16,7 @@
import warnings
from pyasic.miners._types.makes import WhatsMiner
from pyasic.miners.makes import WhatsMiner
class M50SPlusVH30(WhatsMiner): # noqa - ignore ABC method implementation

View File

@@ -16,7 +16,7 @@
import warnings
from pyasic.miners._types.makes import WhatsMiner
from pyasic.miners.makes import WhatsMiner
class M53VH30(WhatsMiner): # noqa - ignore ABC method implementation

View File

@@ -16,7 +16,7 @@
import warnings
from pyasic.miners._types.makes import WhatsMiner
from pyasic.miners.makes import WhatsMiner
class M53SVH30(WhatsMiner): # noqa - ignore ABC method implementation

View File

@@ -16,7 +16,7 @@
import warnings
from pyasic.miners._types.makes import WhatsMiner
from pyasic.miners.makes import WhatsMiner
class M53SPlusVJ30(WhatsMiner): # noqa - ignore ABC method implementation

View File

@@ -16,7 +16,7 @@
import warnings
from pyasic.miners._types.makes import WhatsMiner
from pyasic.miners.makes import WhatsMiner
class M56VH30(WhatsMiner): # noqa - ignore ABC method implementation

View File

@@ -16,7 +16,7 @@
import warnings
from pyasic.miners._types.makes import WhatsMiner
from pyasic.miners.makes import WhatsMiner
class M56SVH30(WhatsMiner): # noqa - ignore ABC method implementation

View File

@@ -16,7 +16,7 @@
import warnings
from pyasic.miners._types.makes import WhatsMiner
from pyasic.miners.makes import WhatsMiner
class M56SPlusVJ30(WhatsMiner): # noqa - ignore ABC method implementation

View File

@@ -16,7 +16,7 @@
import warnings
from pyasic.miners._types.makes import WhatsMiner
from pyasic.miners.makes import WhatsMiner
class M59VH30(WhatsMiner): # noqa - ignore ABC method implementation

Some files were not shown because too many files have changed in this diff Show More