Compare commits
35 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
74b4aeb44a | ||
|
|
9c7ab5ac57 | ||
|
|
65ecf1fea2 | ||
|
|
44142c658b | ||
|
|
25a205ce6c | ||
|
|
25094084cf | ||
|
|
4eac601153 | ||
|
|
f0d8d66b9b | ||
|
|
cfa550f8c0 | ||
|
|
91f6a5bf41 | ||
|
|
464bd6be65 | ||
|
|
031d7e2186 | ||
|
|
126b0d124c | ||
|
|
81c84a3e8f | ||
|
|
406d5bd549 | ||
|
|
cd5fe09fd9 | ||
|
|
766fc4efed | ||
|
|
b70fed40c8 | ||
|
|
255d98fd08 | ||
|
|
78304631f7 | ||
|
|
ab230844fc | ||
|
|
8a58cb9fd3 | ||
|
|
70b6ed73dc | ||
|
|
d2400bf44e | ||
|
|
db780fe876 | ||
|
|
cd84ae828a | ||
|
|
970d5d1031 | ||
|
|
da0e327ec7 | ||
|
|
4c84a8d572 | ||
|
|
1cfd895deb | ||
|
|
d0da08eb10 | ||
|
|
ee4f2cd87d | ||
|
|
8a6577c8aa | ||
|
|
ed5eae4187 | ||
|
|
f3b25027ad |
@@ -9,6 +9,12 @@ repos:
|
||||
rev: 22.6.0
|
||||
hooks:
|
||||
- id: black
|
||||
- repo: https://github.com/pycqa/isort
|
||||
rev: 5.10.1
|
||||
hooks:
|
||||
- id: isort
|
||||
name: isort (python)
|
||||
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: unittest
|
||||
|
||||
@@ -18,6 +18,10 @@ You can install pyasic directly from pip with the command `pip install pyasic`.
|
||||
For those of you who aren't comfortable with code and developer tools, there are windows builds of GUI applications that use this library [here](https://drive.google.com/drive/folders/1DjR8UOS_g0ehfiJcgmrV0FFoqFvE9akW?usp=sharing).
|
||||
|
||||
## Developer Setup
|
||||
It is highly reccommended that you contribute to this project through [`pyasic-super`](https://github.com/UpstreamData/pyasic-super) using its submodules. This allows testing in conjunction with other `pyasic` related programs.
|
||||
|
||||
<br>
|
||||
|
||||
This repo uses poetry for dependencies, which can be installed by following the guide on their website [here](https://python-poetry.org/docs/#installation).
|
||||
|
||||
After you have poetry installed, run `poetry install --with dev`, or `poetry install --with dev,docs` if you want to include packages required for documentation.
|
||||
|
||||
@@ -13,12 +13,12 @@
|
||||
# limitations under the License.
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import ipaddress
|
||||
import warnings
|
||||
import json
|
||||
import logging
|
||||
from typing import Union
|
||||
import re
|
||||
import warnings
|
||||
from typing import Union
|
||||
|
||||
from pyasic.errors import APIError, APIWarning
|
||||
|
||||
@@ -98,7 +98,7 @@ If you are sure you want to use this command please use API.send_command("{comma
|
||||
reader, writer = await asyncio.open_connection(str(self.ip), self.port)
|
||||
# handle OSError 121
|
||||
except OSError as e:
|
||||
if e.winerror == "121":
|
||||
if getattr(e, "winerror") == "121":
|
||||
logging.warning("Semaphore Timeout has Expired.")
|
||||
return b"{}"
|
||||
|
||||
|
||||
@@ -13,8 +13,7 @@
|
||||
# limitations under the License.
|
||||
import logging
|
||||
|
||||
from pyasic.API import BaseMinerAPI
|
||||
from pyasic.API import APIError
|
||||
from pyasic.API import APIError, BaseMinerAPI
|
||||
|
||||
|
||||
class BMMinerAPI(BaseMinerAPI):
|
||||
|
||||
@@ -13,22 +13,21 @@
|
||||
# limitations under the License.
|
||||
|
||||
import asyncio
|
||||
import re
|
||||
import json
|
||||
import hashlib
|
||||
import binascii
|
||||
import base64
|
||||
import binascii
|
||||
import hashlib
|
||||
import json
|
||||
import logging
|
||||
import re
|
||||
from typing import Union
|
||||
|
||||
from passlib.handlers.md5_crypt import md5_crypt
|
||||
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
||||
from passlib.handlers.md5_crypt import md5_crypt
|
||||
|
||||
from pyasic.errors import APIError
|
||||
from pyasic.API import BaseMinerAPI
|
||||
from pyasic.errors import APIError
|
||||
from pyasic.settings import PyasicSettings
|
||||
|
||||
|
||||
### IMPORTANT ###
|
||||
# you need to change the password of the miners using the Whatsminer
|
||||
# tool, then you can set them back to admin with this tool, but they
|
||||
|
||||
@@ -12,10 +12,10 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from pyasic.API import BaseMinerAPI, APIError
|
||||
|
||||
import logging
|
||||
|
||||
from pyasic.API import APIError, BaseMinerAPI
|
||||
|
||||
|
||||
class CGMinerAPI(BaseMinerAPI):
|
||||
"""An abstraction of the CGMiner API.
|
||||
|
||||
@@ -16,26 +16,20 @@ from pyasic.API.bosminer import BOSMinerAPI
|
||||
from pyasic.API.btminer import BTMinerAPI
|
||||
from pyasic.API.cgminer import CGMinerAPI
|
||||
from pyasic.API.unknown import UnknownAPI
|
||||
|
||||
from pyasic.config import MinerConfig
|
||||
|
||||
from pyasic.data import (
|
||||
MinerData,
|
||||
BraiinsOSError,
|
||||
InnosiliconError,
|
||||
MinerData,
|
||||
WhatsminerError,
|
||||
X19Error,
|
||||
)
|
||||
|
||||
from pyasic.errors import APIError, APIWarning
|
||||
|
||||
from pyasic.miners import get_miner
|
||||
from pyasic.miners.base import AnyMiner
|
||||
from pyasic.miners.miner_factory import MinerFactory
|
||||
from pyasic.miners.miner_listener import MinerListener
|
||||
|
||||
from pyasic.network import MinerNetwork
|
||||
|
||||
from pyasic.settings import PyasicSettings
|
||||
|
||||
__all__ = [
|
||||
|
||||
@@ -12,15 +12,15 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from dataclasses import dataclass, asdict, fields
|
||||
from typing import Literal, List
|
||||
import json
|
||||
import random
|
||||
import string
|
||||
import time
|
||||
from dataclasses import asdict, dataclass, fields
|
||||
from typing import List, Literal
|
||||
|
||||
import toml
|
||||
import yaml
|
||||
import json
|
||||
import time
|
||||
|
||||
|
||||
@dataclass
|
||||
|
||||
@@ -12,15 +12,15 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from typing import Union, List
|
||||
from dataclasses import dataclass, field, asdict, fields
|
||||
import copy
|
||||
import json
|
||||
import time
|
||||
from dataclasses import asdict, dataclass, field, fields
|
||||
from datetime import datetime, timezone
|
||||
from functools import reduce
|
||||
import time
|
||||
import json
|
||||
import copy
|
||||
from typing import List, Union
|
||||
|
||||
from .error_codes import X19Error, WhatsminerError, BraiinsOSError, InnosiliconError
|
||||
from .error_codes import BraiinsOSError, InnosiliconError, WhatsminerError, X19Error
|
||||
|
||||
|
||||
@dataclass
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from dataclasses import dataclass, asdict, fields
|
||||
from dataclasses import asdict, dataclass, fields
|
||||
|
||||
|
||||
@dataclass
|
||||
|
||||
@@ -12,13 +12,13 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from .whatsminer import WhatsminerError
|
||||
from .bos import BraiinsOSError
|
||||
from .X19 import X19Error
|
||||
from .innosilicon import InnosiliconError
|
||||
|
||||
from typing import TypeVar
|
||||
|
||||
from .bos import BraiinsOSError
|
||||
from .innosilicon import InnosiliconError
|
||||
from .whatsminer import WhatsminerError
|
||||
from .X19 import X19Error
|
||||
|
||||
MinerErrorData = TypeVar(
|
||||
"MinerErrorData", WhatsminerError, BraiinsOSError, X19Error, InnosiliconError
|
||||
)
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from dataclasses import dataclass, asdict, fields
|
||||
from dataclasses import asdict, dataclass, fields
|
||||
|
||||
|
||||
@dataclass
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from dataclasses import dataclass, field, asdict, fields
|
||||
from dataclasses import asdict, dataclass, field, fields
|
||||
|
||||
|
||||
@dataclass
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from dataclasses import dataclass, field, asdict, fields
|
||||
from dataclasses import asdict, dataclass, field, fields
|
||||
|
||||
|
||||
@dataclass
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
# limitations under the License.
|
||||
|
||||
import logging
|
||||
|
||||
from pyasic.settings import PyasicSettings
|
||||
|
||||
|
||||
|
||||
@@ -15,9 +15,10 @@
|
||||
import ipaddress
|
||||
from typing import Union
|
||||
|
||||
from pyasic.miners.base import BaseMiner, AnyMiner
|
||||
from pyasic.miners.base import AnyMiner, BaseMiner
|
||||
from pyasic.miners.miner_factory import MinerFactory
|
||||
|
||||
|
||||
# abstracted version of get miner that is easier to access
|
||||
async def get_miner(ip: Union[ipaddress.ip_address, str]) -> AnyMiner:
|
||||
return await MinerFactory().get_miner(ip)
|
||||
|
||||
@@ -14,16 +14,13 @@
|
||||
|
||||
import ipaddress
|
||||
import logging
|
||||
from typing import Union, List
|
||||
|
||||
from typing import List, Union
|
||||
|
||||
from pyasic.API.bmminer import BMMinerAPI
|
||||
from pyasic.miners.base import BaseMiner
|
||||
|
||||
from pyasic.data import MinerData, HashBoard
|
||||
from pyasic.config import MinerConfig
|
||||
from pyasic.data import HashBoard, MinerData
|
||||
from pyasic.data.error_codes import MinerErrorData
|
||||
|
||||
from pyasic.miners.base import BaseMiner
|
||||
from pyasic.settings import PyasicSettings
|
||||
|
||||
|
||||
|
||||
@@ -13,22 +13,19 @@
|
||||
# limitations under the License.
|
||||
|
||||
import ipaddress
|
||||
import logging
|
||||
import json
|
||||
from typing import Union, List
|
||||
import logging
|
||||
from typing import List, Union
|
||||
|
||||
import toml
|
||||
import httpx
|
||||
|
||||
|
||||
from pyasic.miners.base import BaseMiner
|
||||
from pyasic.API.bosminer import BOSMinerAPI
|
||||
from pyasic.errors import APIError
|
||||
|
||||
from pyasic.data.error_codes import BraiinsOSError, MinerErrorData
|
||||
from pyasic.data import MinerData, HashBoard
|
||||
|
||||
from pyasic.config import MinerConfig
|
||||
|
||||
from pyasic.data import HashBoard, MinerData
|
||||
from pyasic.data.error_codes import BraiinsOSError, MinerErrorData
|
||||
from pyasic.errors import APIError
|
||||
from pyasic.miners.base import BaseMiner
|
||||
from pyasic.settings import PyasicSettings
|
||||
|
||||
|
||||
@@ -69,6 +66,27 @@ class BOSMiner(BaseMiner):
|
||||
# return the result, either command output or None
|
||||
return str(result)
|
||||
|
||||
async def send_graphql_query(self, query) -> Union[dict, None]:
|
||||
url = f"http://{self.ip}/graphql"
|
||||
try:
|
||||
async with httpx.AsyncClient() as client:
|
||||
_auth = await client.post(
|
||||
url,
|
||||
json={
|
||||
"query": 'mutation{auth{login(username:"'
|
||||
+ self.uname
|
||||
+ '", password:"'
|
||||
+ self.pwd
|
||||
+ '"){__typename}}}'
|
||||
},
|
||||
)
|
||||
d = await client.post(url, json={"query": query})
|
||||
if d.status_code == 200:
|
||||
return d.json()
|
||||
except httpx.ReadError:
|
||||
return None
|
||||
return None
|
||||
|
||||
async def fault_light_on(self) -> bool:
|
||||
"""Sends command to turn on fault light on the miner."""
|
||||
logging.debug(f"{self}: Sending fault_light on command.")
|
||||
@@ -152,6 +170,11 @@ class BOSMiner(BaseMiner):
|
||||
"""
|
||||
if self.hostname:
|
||||
return self.hostname
|
||||
# get hostname through GraphQL
|
||||
if data := await self.send_graphql_query("{bos {hostname}}"):
|
||||
self.hostname = data["data"]["bos"]["hostname"]
|
||||
return self.hostname
|
||||
|
||||
try:
|
||||
async with (await self._get_ssh_connection()) as conn:
|
||||
if conn is not None:
|
||||
@@ -215,9 +238,15 @@ class BOSMiner(BaseMiner):
|
||||
if self.version:
|
||||
logging.debug(f"Found version for {self.ip}: {self.version}")
|
||||
return self.version
|
||||
version_data = None
|
||||
# try to get data from graphql
|
||||
data = await self.send_graphql_query("{bos{info{version{full}}}}")
|
||||
if data:
|
||||
version_data = data["bos"]["info"]["version"]["full"]
|
||||
|
||||
# get output of bos version file
|
||||
version_data = await self.send_ssh_command("cat /etc/bos_version")
|
||||
if not version_data:
|
||||
# try version data file
|
||||
version_data = await self.send_ssh_command("cat /etc/bos_version")
|
||||
|
||||
# if we get the version data, parse it
|
||||
if version_data:
|
||||
@@ -248,6 +277,15 @@ class BOSMiner(BaseMiner):
|
||||
async def check_light(self) -> bool:
|
||||
if self.light:
|
||||
return self.light
|
||||
# get light through GraphQL
|
||||
if data := await self.send_graphql_query("{bos {faultLight}}"):
|
||||
try:
|
||||
self.light = data["data"]["bos"]["faultLight"]
|
||||
return self.light
|
||||
except (TypeError, KeyError, ValueError, IndexError):
|
||||
pass
|
||||
|
||||
# get light via ssh if that fails (10x slower)
|
||||
data = (
|
||||
await self.send_ssh_command("cat /sys/class/leds/'Red LED'/delay_off")
|
||||
).strip()
|
||||
@@ -289,6 +327,7 @@ class BOSMiner(BaseMiner):
|
||||
if board["Status"] not in [
|
||||
"Stable",
|
||||
"Testing performance profile",
|
||||
"Tuning individual chips"
|
||||
]:
|
||||
_error = board["Status"].split(" {")[0]
|
||||
_error = _error[0].lower() + _error[1:]
|
||||
@@ -303,6 +342,10 @@ class BOSMiner(BaseMiner):
|
||||
Returns:
|
||||
A [`MinerData`][pyasic.data.MinerData] instance containing the miners data.
|
||||
"""
|
||||
d = await self._graphql_get_data()
|
||||
if d:
|
||||
return d
|
||||
|
||||
data = MinerData(
|
||||
ip=str(self.ip),
|
||||
ideal_chips=self.nominal_chips * self.ideal_hashboards,
|
||||
@@ -342,7 +385,7 @@ class BOSMiner(BaseMiner):
|
||||
"devdetails",
|
||||
"fans",
|
||||
"devs",
|
||||
allow_warning=allow_warning
|
||||
allow_warning=allow_warning,
|
||||
)
|
||||
except APIError as e:
|
||||
if str(e.message) == "Not ready":
|
||||
@@ -493,6 +536,139 @@ class BOSMiner(BaseMiner):
|
||||
data.hashboards[_id].hashrate = hashrate
|
||||
return data
|
||||
|
||||
async def _graphql_get_data(self) -> Union[MinerData, None]:
|
||||
data = MinerData(
|
||||
ip=str(self.ip),
|
||||
ideal_chips=self.nominal_chips * self.ideal_hashboards,
|
||||
ideal_hashboards=self.ideal_hashboards,
|
||||
hashboards=[
|
||||
HashBoard(slot=i, expected_chips=self.nominal_chips, missing=True)
|
||||
for i in range(self.ideal_hashboards)
|
||||
],
|
||||
)
|
||||
query = "{bos {hostname}, bosminer{config{... on BosminerConfig{groups{pools{url, user}, strategy{... on QuotaStrategy {quota}}}}}, info{fans{name, rpm}, workSolver{realHashrate{mhs1M}, temperatures{degreesC}, power{limitW, approxConsumptionW}, childSolvers{name, realHashrate{mhs1M}, hwDetails{chips}, tuner{statusMessages}, temperatures{degreesC}}}}}}"
|
||||
query_data = await self.send_graphql_query(query)
|
||||
if not query_data:
|
||||
return None
|
||||
query_data = query_data["data"]
|
||||
|
||||
data.mac = await self.get_mac()
|
||||
data.model = await self.get_model()
|
||||
if query_data.get("bos"):
|
||||
if query_data["bos"].get("hostname"):
|
||||
data.hostname = query_data["bos"]["hostname"]
|
||||
|
||||
try:
|
||||
if query_data["bosminer"]["info"]["workSolver"]["realHashrate"].get("mhs1M"):
|
||||
data.hashrate = round(
|
||||
query_data["bosminer"]["info"]["workSolver"]["realHashrate"]["mhs1M"]
|
||||
/ 1000000,
|
||||
2,
|
||||
)
|
||||
except (TypeError, KeyError, ValueError, IndexError):
|
||||
pass
|
||||
|
||||
boards = None
|
||||
if query_data.get("bosminer"):
|
||||
if query_data["bosminer"].get("info"):
|
||||
if query_data["bosminer"]["info"].get("workSolver"):
|
||||
boards = query_data["bosminer"]["info"]["workSolver"].get("childSolvers")
|
||||
if boards:
|
||||
offset = 6 if int(boards[0]["name"]) in [6, 7, 8] else int(boards[0]["name"])
|
||||
for hb in boards:
|
||||
_id = int(hb["name"]) - offset
|
||||
|
||||
board = data.hashboards[_id]
|
||||
board.hashrate = round(hb["realHashrate"]["mhs1M"] / 1000000, 2)
|
||||
temps = hb["temperatures"]
|
||||
try:
|
||||
if len(temps) > 0:
|
||||
board.temp = round(hb["temperatures"][0]["degreesC"])
|
||||
if len(temps) > 1:
|
||||
board.chip_temp = round(hb["temperatures"][1]["degreesC"])
|
||||
except (TypeError, KeyError, ValueError, IndexError):
|
||||
pass
|
||||
details = hb.get("hwDetails")
|
||||
if details:
|
||||
if chips := details["chips"]:
|
||||
board.chips = chips
|
||||
board.missing = False
|
||||
|
||||
tuner = hb.get("tuner")
|
||||
if tuner:
|
||||
if msg := tuner.get("statusMessages"):
|
||||
if len(msg) > 0:
|
||||
if hb["tuner"]["statusMessages"][0] not in [
|
||||
"Stable",
|
||||
"Testing performance profile",
|
||||
"Tuning individual chips"
|
||||
]:
|
||||
data.errors.append(
|
||||
BraiinsOSError(f"Slot {_id} {hb['tuner']['statusMessages'][0]}")
|
||||
)
|
||||
try:
|
||||
data.wattage = query_data["bosminer"]["info"]["workSolver"]["power"]["approxConsumptionW"]
|
||||
except (TypeError, KeyError, ValueError, IndexError):
|
||||
pass
|
||||
try:
|
||||
data.wattage_limit = query_data["bosminer"]["info"]["workSolver"]["power"]["limitW"]
|
||||
except (TypeError, KeyError, ValueError, IndexError):
|
||||
pass
|
||||
|
||||
|
||||
for n in range(self.fan_count):
|
||||
try:
|
||||
setattr(data, f"fan_{n + 1}", query_data["bosminer"]["info"]["fans"][n]["rpm"])
|
||||
except (TypeError, KeyError, ValueError, IndexError):
|
||||
pass
|
||||
|
||||
groups = None
|
||||
if query_data.get("bosminer"):
|
||||
if query_data["bosminer"].get("config"):
|
||||
groups = query_data["bosminer"]["config"].get("groups")
|
||||
if groups:
|
||||
if len(groups) == 1:
|
||||
try:
|
||||
data.pool_1_user = groups[0]["pools"][0]["user"]
|
||||
except (TypeError, KeyError, ValueError, IndexError):
|
||||
pass
|
||||
try:
|
||||
data.pool_1_url = groups[0]["pools"][0]["url"]
|
||||
except (TypeError, KeyError, ValueError, IndexError):
|
||||
pass
|
||||
try:
|
||||
data.pool_2_user = groups[0]["pools"][1]["user"]
|
||||
except (TypeError, KeyError, ValueError, IndexError):
|
||||
pass
|
||||
try:
|
||||
data.pool_2_url = groups[0]["pools"][1]["url"]
|
||||
except (TypeError, KeyError, ValueError, IndexError):
|
||||
pass
|
||||
data.quota = 0
|
||||
else:
|
||||
try:
|
||||
data.pool_1_user = groups[0]["pools"][0]["user"]
|
||||
except (TypeError, KeyError, ValueError, IndexError):
|
||||
pass
|
||||
try:
|
||||
data.pool_1_url = groups[0]["pools"][0]["url"]
|
||||
except (TypeError, KeyError, ValueError, IndexError):
|
||||
pass
|
||||
try:
|
||||
data.pool_2_user = groups[1]["pools"][0]["user"]
|
||||
except (TypeError, KeyError, ValueError, IndexError):
|
||||
pass
|
||||
try:
|
||||
data.pool_2_url = groups[1]["pools"][0]["url"]
|
||||
except (TypeError, KeyError, ValueError, IndexError):
|
||||
pass
|
||||
if groups[0]["strategy"].get("quota"):
|
||||
data.quota = groups[0]["strategy"]["quota"] + "/" + groups[1]["strategy"]["quota"]
|
||||
|
||||
data.fault_light = await self.check_light()
|
||||
|
||||
return data
|
||||
|
||||
async def get_mac(self):
|
||||
result = await self.send_ssh_command("cat /sys/class/net/eth0/address")
|
||||
return result.upper().strip()
|
||||
|
||||
@@ -12,16 +12,15 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import logging
|
||||
|
||||
import ipaddress
|
||||
from typing import Union, List
|
||||
import logging
|
||||
from typing import List, Union
|
||||
|
||||
from pyasic.API.bosminer import BOSMinerAPI
|
||||
from pyasic.miners.base import BaseMiner
|
||||
from pyasic.config import MinerConfig
|
||||
from pyasic.data import MinerData
|
||||
from pyasic.data.error_codes import MinerErrorData
|
||||
from pyasic.miners.base import BaseMiner
|
||||
|
||||
|
||||
class BOSMinerOld(BaseMiner):
|
||||
|
||||
@@ -14,17 +14,14 @@
|
||||
|
||||
import ipaddress
|
||||
import logging
|
||||
from typing import Union, List
|
||||
|
||||
from typing import List, Union
|
||||
|
||||
from pyasic.API.btminer import BTMinerAPI
|
||||
from pyasic.miners.base import BaseMiner
|
||||
from pyasic.errors import APIError
|
||||
|
||||
from pyasic.data import MinerData, HashBoard
|
||||
from pyasic.data.error_codes import WhatsminerError, MinerErrorData
|
||||
from pyasic.config import MinerConfig
|
||||
|
||||
from pyasic.data import HashBoard, MinerData
|
||||
from pyasic.data.error_codes import MinerErrorData, WhatsminerError
|
||||
from pyasic.errors import APIError
|
||||
from pyasic.miners.base import BaseMiner
|
||||
from pyasic.settings import PyasicSettings
|
||||
|
||||
|
||||
|
||||
@@ -14,17 +14,14 @@
|
||||
|
||||
import ipaddress
|
||||
import logging
|
||||
from typing import Union, List
|
||||
|
||||
from typing import List, Union
|
||||
|
||||
from pyasic.API.cgminer import CGMinerAPI
|
||||
from pyasic.miners.base import BaseMiner
|
||||
from pyasic.errors import APIError
|
||||
from pyasic.config import MinerConfig
|
||||
|
||||
from pyasic.data import MinerData, HashBoard
|
||||
from pyasic.data import HashBoard, MinerData
|
||||
from pyasic.data.error_codes import MinerErrorData
|
||||
|
||||
from pyasic.errors import APIError
|
||||
from pyasic.miners.base import BaseMiner
|
||||
from pyasic.settings import PyasicSettings
|
||||
|
||||
|
||||
|
||||
@@ -12,9 +12,10 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from pyasic.miners._backends import BMMiner
|
||||
import ipaddress
|
||||
|
||||
from pyasic.miners._backends import BMMiner
|
||||
|
||||
|
||||
class Hiveon(BMMiner):
|
||||
def __init__(self, ip: str) -> None:
|
||||
|
||||
@@ -14,5 +14,5 @@
|
||||
|
||||
from .antminer import *
|
||||
from .avalonminer import *
|
||||
from .whatsminer import *
|
||||
from .innosilicon import *
|
||||
from .whatsminer import *
|
||||
|
||||
@@ -16,7 +16,6 @@ from .S17 import S17
|
||||
from .S17_Plus import S17Plus
|
||||
from .S17_Pro import S17Pro
|
||||
from .S17e import S17e
|
||||
|
||||
from .T17 import T17
|
||||
from .T17_Plus import T17Plus
|
||||
from .T17e import T17e
|
||||
|
||||
@@ -14,12 +14,8 @@
|
||||
|
||||
from .S19 import S19
|
||||
from .S19_Pro import S19Pro
|
||||
|
||||
from .S19_XP import S19XP
|
||||
from .S19a import S19a
|
||||
from .S19j import S19j
|
||||
from .S19j_Pro import S19jPro
|
||||
|
||||
from .S19_XP import S19XP
|
||||
|
||||
from .S19a import S19a
|
||||
|
||||
from .T19 import T19
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
from .M20 import M20, M20V10
|
||||
from .M20S import M20S, M20SV10, M20SV20
|
||||
from .M20S_Plus import M20SPlus
|
||||
|
||||
from .M21 import M21
|
||||
from .M21S import M21S, M21SV20, M21SV60
|
||||
from .M21S_Plus import M21SPlus
|
||||
|
||||
@@ -12,26 +12,24 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from .M30S import M30S, M30SVE10, M30SVE20, M30SVG20, M30SV50
|
||||
from .M30S_Plus import M30SPlus, M30SPlusVG60, M30SPlusVE40, M30SPlusVF20
|
||||
from .M30S import M30S, M30SV50, M30SVE10, M30SVE20, M30SVG20
|
||||
from .M30S_Plus import M30SPlus, M30SPlusVE40, M30SPlusVF20, M30SPlusVG60
|
||||
from .M30S_Plus_Plus import (
|
||||
M30SPlusPlus,
|
||||
M30SPlusPlusVG30,
|
||||
M30SPlusPlusVG40,
|
||||
M30SPlusPlusVH60,
|
||||
)
|
||||
|
||||
from .M31S import M31S
|
||||
from .M31S_Plus import (
|
||||
M31SPlus,
|
||||
M31SPlusVE20,
|
||||
M31SPlusV30,
|
||||
M31SPlusV40,
|
||||
M31SPlusV80,
|
||||
M31SPlusV60,
|
||||
M31SPlusV80,
|
||||
M31SPlusV90,
|
||||
M31SPlusVE20,
|
||||
)
|
||||
|
||||
from .M32 import M32, M32V20
|
||||
from .M32S import M32S
|
||||
from .M34S_Plus import M34SPlus, M34SPlusVE10
|
||||
|
||||
@@ -12,9 +12,10 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from .X17 import BMMinerX17
|
||||
from pyasic.miners._types import S17 # noqa - Ignore access to _module
|
||||
|
||||
from .X17 import BMMinerX17
|
||||
|
||||
|
||||
class BMMinerS17(BMMinerX17, S17):
|
||||
def __init__(self, ip: str) -> None:
|
||||
|
||||
@@ -12,9 +12,10 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from .X17 import BMMinerX17
|
||||
from pyasic.miners._types import S17Plus # noqa - Ignore access to _module
|
||||
|
||||
from .X17 import BMMinerX17
|
||||
|
||||
|
||||
class BMMinerS17Plus(BMMinerX17, S17Plus):
|
||||
def __init__(self, ip: str) -> None:
|
||||
|
||||
@@ -12,9 +12,10 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from .X17 import BMMinerX17
|
||||
from pyasic.miners._types import S17Pro # noqa - Ignore access to _module
|
||||
|
||||
from .X17 import BMMinerX17
|
||||
|
||||
|
||||
class BMMinerS17Pro(BMMinerX17, S17Pro):
|
||||
def __init__(self, ip: str) -> None:
|
||||
|
||||
@@ -12,9 +12,10 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from .X17 import BMMinerX17
|
||||
from pyasic.miners._types import S17e # noqa - Ignore access to _module
|
||||
|
||||
from .X17 import BMMinerX17
|
||||
|
||||
|
||||
class BMMinerS17e(BMMinerX17, S17e):
|
||||
def __init__(self, ip: str) -> None:
|
||||
|
||||
@@ -12,9 +12,10 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from .X17 import BMMinerX17
|
||||
from pyasic.miners._types import T17 # noqa - Ignore access to _module
|
||||
|
||||
from .X17 import BMMinerX17
|
||||
|
||||
|
||||
class BMMinerT17(BMMinerX17, T17):
|
||||
def __init__(self, ip: str) -> None:
|
||||
|
||||
@@ -12,9 +12,10 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from .X17 import BMMinerX17
|
||||
from pyasic.miners._types import T17Plus # noqa - Ignore access to _module
|
||||
|
||||
from .X17 import BMMinerX17
|
||||
|
||||
|
||||
class BMMinerT17Plus(BMMinerX17, T17Plus):
|
||||
def __init__(self, ip: str) -> None:
|
||||
|
||||
@@ -12,9 +12,10 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from .X17 import BMMinerX17
|
||||
from pyasic.miners._types import T17e # noqa - Ignore access to _module
|
||||
|
||||
from .X17 import BMMinerX17
|
||||
|
||||
|
||||
class BMMinerT17e(BMMinerX17, T17e):
|
||||
def __init__(self, ip: str) -> None:
|
||||
|
||||
@@ -12,12 +12,12 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from pyasic.miners._backends import BMMiner # noqa - Ignore access to _module
|
||||
|
||||
from pyasic.settings import PyasicSettings
|
||||
from typing import Union
|
||||
|
||||
import httpx
|
||||
from typing import Union
|
||||
|
||||
from pyasic.miners._backends import BMMiner # noqa - Ignore access to _module
|
||||
from pyasic.settings import PyasicSettings
|
||||
|
||||
|
||||
class BMMinerX17(BMMiner):
|
||||
|
||||
@@ -16,7 +16,6 @@ from .S17 import BMMinerS17
|
||||
from .S17_Plus import BMMinerS17Plus
|
||||
from .S17_Pro import BMMinerS17Pro
|
||||
from .S17e import BMMinerS17e
|
||||
|
||||
from .T17 import BMMinerT17
|
||||
from .T17_Plus import BMMinerT17Plus
|
||||
from .T17e import BMMinerT17e
|
||||
|
||||
@@ -12,9 +12,10 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from .X19 import BMMinerX19
|
||||
from pyasic.miners._types import S19 # noqa - Ignore access to _module
|
||||
|
||||
from .X19 import BMMinerX19
|
||||
|
||||
|
||||
class BMMinerS19(BMMinerX19, S19):
|
||||
def __init__(self, ip: str) -> None:
|
||||
|
||||
@@ -12,9 +12,10 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from .X19 import BMMinerX19
|
||||
from pyasic.miners._types import S19Pro # noqa - Ignore access to _module
|
||||
|
||||
from .X19 import BMMinerX19
|
||||
|
||||
|
||||
class BMMinerS19Pro(BMMinerX19, S19Pro):
|
||||
def __init__(self, ip: str) -> None:
|
||||
|
||||
@@ -12,9 +12,10 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from .X19 import BMMinerX19
|
||||
from pyasic.miners._types import S19XP # noqa - Ignore access to _module
|
||||
|
||||
from .X19 import BMMinerX19
|
||||
|
||||
|
||||
class BMMinerS19XP(BMMinerX19, S19XP):
|
||||
def __init__(self, ip: str) -> None:
|
||||
|
||||
@@ -12,9 +12,10 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from .X19 import BMMinerX19
|
||||
from pyasic.miners._types import S19a # noqa - Ignore access to _module
|
||||
|
||||
from .X19 import BMMinerX19
|
||||
|
||||
|
||||
class BMMinerS19a(BMMinerX19, S19a):
|
||||
def __init__(self, ip: str) -> None:
|
||||
|
||||
@@ -12,9 +12,10 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from .X19 import BMMinerX19
|
||||
from pyasic.miners._types import S19j # noqa - Ignore access to _module
|
||||
|
||||
from .X19 import BMMinerX19
|
||||
|
||||
|
||||
class BMMinerS19j(BMMinerX19, S19j):
|
||||
def __init__(self, ip: str) -> None:
|
||||
|
||||
@@ -12,9 +12,10 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from .X19 import BMMinerX19
|
||||
from pyasic.miners._types import S19jPro # noqa - Ignore access to _module
|
||||
|
||||
from .X19 import BMMinerX19
|
||||
|
||||
|
||||
class BMMinerS19jPro(BMMinerX19, S19jPro):
|
||||
def __init__(self, ip: str) -> None:
|
||||
|
||||
@@ -12,9 +12,10 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from .X19 import BMMinerX19
|
||||
from pyasic.miners._types import T19 # noqa - Ignore access to _module
|
||||
|
||||
from .X19 import BMMinerX19
|
||||
|
||||
|
||||
class BMMinerT19(BMMinerX19, T19):
|
||||
def __init__(self, ip: str) -> None:
|
||||
|
||||
@@ -12,16 +12,16 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from pyasic.miners._backends import BMMiner # noqa - Ignore access to _module
|
||||
|
||||
from pyasic.config import MinerConfig
|
||||
from pyasic.data.error_codes import X19Error, MinerErrorData
|
||||
from pyasic.settings import PyasicSettings
|
||||
import asyncio
|
||||
import json
|
||||
from typing import List, Union
|
||||
|
||||
import httpx
|
||||
import json
|
||||
import asyncio
|
||||
from typing import Union, List
|
||||
|
||||
from pyasic.config import MinerConfig
|
||||
from pyasic.data.error_codes import MinerErrorData, X19Error
|
||||
from pyasic.miners._backends import BMMiner # noqa - Ignore access to _module
|
||||
from pyasic.settings import PyasicSettings
|
||||
|
||||
|
||||
class BMMinerX19(BMMiner):
|
||||
|
||||
@@ -14,12 +14,8 @@
|
||||
|
||||
from .S19 import BMMinerS19
|
||||
from .S19_Pro import BMMinerS19Pro
|
||||
|
||||
from .S19_XP import BMMinerS19XP
|
||||
from .S19a import BMMinerS19a
|
||||
from .S19j import BMMinerS19j
|
||||
from .S19j_Pro import BMMinerS19jPro
|
||||
|
||||
from .S19_XP import BMMinerS19XP
|
||||
|
||||
from .S19a import BMMinerS19a
|
||||
|
||||
from .T19 import BMMinerT19
|
||||
|
||||
@@ -16,7 +16,6 @@ from .S17 import BOSMinerS17
|
||||
from .S17_Plus import BOSMinerS17Plus
|
||||
from .S17_Pro import BOSMinerS17Pro
|
||||
from .S17e import BOSMinerS17e
|
||||
|
||||
from .T17 import BOSMinerT17
|
||||
from .T17_Plus import BOSMinerT17Plus
|
||||
from .T17e import BOSMinerT17e
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
|
||||
from .S19 import BOSMinerS19
|
||||
from .S19_Pro import BOSMinerS19Pro
|
||||
|
||||
from .S19j import BOSMinerS19j
|
||||
from .S19j_Pro import BOSMinerS19jPro
|
||||
|
||||
from .T19 import BOSMinerT19
|
||||
|
||||
@@ -16,7 +16,6 @@ from .S17 import CGMinerS17
|
||||
from .S17_Plus import CGMinerS17Plus
|
||||
from .S17_Pro import CGMinerS17Pro
|
||||
from .S17e import CGMinerS17e
|
||||
|
||||
from .T17 import CGMinerT17
|
||||
from .T17_Plus import CGMinerT17Plus
|
||||
from .T17e import CGMinerT17e
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
|
||||
from .S19 import CGMinerS19
|
||||
from .S19_Pro import CGMinerS19Pro
|
||||
|
||||
from .S19j import CGMinerS19j
|
||||
from .S19j_Pro import CGMinerS19jPro
|
||||
|
||||
from .T19 import CGMinerT19
|
||||
|
||||
@@ -12,10 +12,9 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from pyasic.data import HashBoard, MinerData
|
||||
from pyasic.miners._backends import Hiveon # noqa - Ignore access to _module
|
||||
from pyasic.miners._types import T9 # noqa - Ignore access to _module
|
||||
|
||||
from pyasic.data import MinerData, HashBoard
|
||||
from pyasic.settings import PyasicSettings
|
||||
|
||||
|
||||
|
||||
@@ -12,9 +12,10 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from .A10X import CGMinerA10X
|
||||
from pyasic.miners._types import Avalon1026 # noqa - Ignore access to _module
|
||||
|
||||
from .A10X import CGMinerA10X
|
||||
|
||||
|
||||
class CGMinerAvalon1026(CGMinerA10X, Avalon1026):
|
||||
def __init__(self, ip: str) -> None:
|
||||
|
||||
@@ -12,9 +12,10 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from .A10X import CGMinerA10X
|
||||
from pyasic.miners._types import Avalon1047 # noqa - Ignore access to _module
|
||||
|
||||
from .A10X import CGMinerA10X
|
||||
|
||||
|
||||
class CGMinerAvalon1047(CGMinerA10X, Avalon1047):
|
||||
def __init__(self, ip: str) -> None:
|
||||
|
||||
@@ -12,9 +12,10 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from .A10X import CGMinerA10X
|
||||
from pyasic.miners._types import Avalon1066 # noqa - Ignore access to _module
|
||||
|
||||
from .A10X import CGMinerA10X
|
||||
|
||||
|
||||
class CGMinerAvalon1066(CGMinerA10X, Avalon1066):
|
||||
def __init__(self, ip: str) -> None:
|
||||
|
||||
@@ -12,13 +12,13 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from pyasic.miners._backends import CGMiner # noqa - Ignore access to _module
|
||||
|
||||
from pyasic.data import MinerData, HashBoard
|
||||
from pyasic.settings import PyasicSettings
|
||||
import re
|
||||
from pyasic.config import MinerConfig
|
||||
import logging
|
||||
import re
|
||||
|
||||
from pyasic.config import MinerConfig
|
||||
from pyasic.data import HashBoard, MinerData
|
||||
from pyasic.miners._backends import CGMiner # noqa - Ignore access to _module
|
||||
from pyasic.settings import PyasicSettings
|
||||
|
||||
|
||||
class CGMinerA10X(CGMiner):
|
||||
|
||||
@@ -12,9 +12,10 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from .A7X import CGMinerA7X # noqa - Ignore access to _module
|
||||
from pyasic.miners._types import Avalon721 # noqa - Ignore access to _module
|
||||
|
||||
from .A7X import CGMinerA7X # noqa - Ignore access to _module
|
||||
|
||||
|
||||
class CGMinerAvalon721(CGMinerA7X, Avalon721):
|
||||
def __init__(self, ip: str) -> None:
|
||||
|
||||
@@ -12,9 +12,10 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from .A7X import CGMinerA7X # noqa - Ignore access to _module
|
||||
from pyasic.miners._types import Avalon741 # noqa - Ignore access to _module
|
||||
|
||||
from .A7X import CGMinerA7X # noqa - Ignore access to _module
|
||||
|
||||
|
||||
class CGMinerAvalon741(CGMinerA7X, Avalon741):
|
||||
def __init__(self, ip: str) -> None:
|
||||
|
||||
@@ -12,9 +12,10 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from .A7X import CGMinerA7X # noqa - Ignore access to _module
|
||||
from pyasic.miners._types import Avalon761 # noqa - Ignore access to _module
|
||||
|
||||
from .A7X import CGMinerA7X # noqa - Ignore access to _module
|
||||
|
||||
|
||||
class CGMinerAvalon761(CGMinerA7X, Avalon761):
|
||||
def __init__(self, ip: str) -> None:
|
||||
|
||||
@@ -12,13 +12,13 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from pyasic.miners._backends import CGMiner # noqa - Ignore access to _module
|
||||
|
||||
from pyasic.data import MinerData, HashBoard
|
||||
from pyasic.settings import PyasicSettings
|
||||
import re
|
||||
from pyasic.config import MinerConfig
|
||||
import logging
|
||||
import re
|
||||
|
||||
from pyasic.config import MinerConfig
|
||||
from pyasic.data import HashBoard, MinerData
|
||||
from pyasic.miners._backends import CGMiner # noqa - Ignore access to _module
|
||||
from pyasic.settings import PyasicSettings
|
||||
|
||||
|
||||
class CGMinerA7X(CGMiner):
|
||||
|
||||
@@ -12,9 +12,10 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from .A8X import CGMinerA8X # noqa - Ignore access to _module
|
||||
from pyasic.miners._types import Avalon821 # noqa - Ignore access to _module
|
||||
|
||||
from .A8X import CGMinerA8X # noqa - Ignore access to _module
|
||||
|
||||
|
||||
class CGMinerAvalon821(CGMinerA8X, Avalon821):
|
||||
def __init__(self, ip: str) -> None:
|
||||
|
||||
@@ -12,9 +12,10 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from .A8X import CGMinerA8X # noqa - Ignore access to _module
|
||||
from pyasic.miners._types import Avalon841 # noqa - Ignore access to _module
|
||||
|
||||
from .A8X import CGMinerA8X # noqa - Ignore access to _module
|
||||
|
||||
|
||||
class CGMinerAvalon841(CGMinerA8X, Avalon841):
|
||||
def __init__(self, ip: str) -> None:
|
||||
|
||||
@@ -12,9 +12,10 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from .A8X import CGMinerA8X # noqa - Ignore access to _module
|
||||
from pyasic.miners._types import Avalon851 # noqa - Ignore access to _module
|
||||
|
||||
from .A8X import CGMinerA8X # noqa - Ignore access to _module
|
||||
|
||||
|
||||
class CGMinerAvalon851(CGMinerA8X, Avalon851):
|
||||
def __init__(self, ip: str) -> None:
|
||||
|
||||
@@ -12,13 +12,13 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from pyasic.miners._backends import CGMiner # noqa - Ignore access to _module
|
||||
|
||||
from pyasic.data import MinerData, HashBoard
|
||||
from pyasic.settings import PyasicSettings
|
||||
import re
|
||||
from pyasic.config import MinerConfig
|
||||
import logging
|
||||
import re
|
||||
|
||||
from pyasic.config import MinerConfig
|
||||
from pyasic.data import HashBoard, MinerData
|
||||
from pyasic.miners._backends import CGMiner # noqa - Ignore access to _module
|
||||
from pyasic.settings import PyasicSettings
|
||||
|
||||
|
||||
class CGMinerA8X(CGMiner):
|
||||
|
||||
@@ -12,14 +12,14 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import logging
|
||||
import re
|
||||
|
||||
from pyasic.config import MinerConfig
|
||||
from pyasic.data import HashBoard, MinerData
|
||||
from pyasic.miners._backends import CGMiner # noqa - Ignore access to _module
|
||||
from pyasic.miners._types import Avalon921 # noqa - Ignore access to _module
|
||||
|
||||
from pyasic.data import MinerData, HashBoard
|
||||
from pyasic.settings import PyasicSettings
|
||||
import re
|
||||
from pyasic.config import MinerConfig
|
||||
import logging
|
||||
|
||||
|
||||
class CGMinerAvalon921(CGMiner, Avalon921):
|
||||
|
||||
@@ -12,20 +12,21 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import asyncssh
|
||||
import logging
|
||||
import ipaddress
|
||||
import logging
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import TypeVar, List, Union
|
||||
from typing import List, TypeVar, Union
|
||||
|
||||
import asyncssh
|
||||
|
||||
from pyasic.data import MinerData
|
||||
from pyasic.config import MinerConfig
|
||||
from pyasic.data import MinerData
|
||||
from pyasic.data.error_codes import (
|
||||
WhatsminerError,
|
||||
BraiinsOSError,
|
||||
InnosiliconError,
|
||||
X19Error,
|
||||
MinerErrorData,
|
||||
WhatsminerError,
|
||||
X19Error,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -12,18 +12,19 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from pyasic.miners._backends import CGMiner # noqa - Ignore access to _module
|
||||
from pyasic.miners._types import InnosiliconT3HPlus # noqa - Ignore access to _module
|
||||
from pyasic.data import MinerData, HashBoard
|
||||
from pyasic.data.error_codes import InnosiliconError, MinerErrorData
|
||||
from pyasic.settings import PyasicSettings
|
||||
from pyasic.config import MinerConfig
|
||||
from pyasic.errors import APIError
|
||||
import logging
|
||||
import warnings
|
||||
from typing import List, Union
|
||||
|
||||
import httpx
|
||||
import warnings
|
||||
from typing import Union, List
|
||||
import logging
|
||||
|
||||
from pyasic.config import MinerConfig
|
||||
from pyasic.data import HashBoard, MinerData
|
||||
from pyasic.data.error_codes import InnosiliconError, MinerErrorData
|
||||
from pyasic.errors import APIError
|
||||
from pyasic.miners._backends import CGMiner # noqa - Ignore access to _module
|
||||
from pyasic.miners._types import InnosiliconT3HPlus # noqa - Ignore access to _module
|
||||
from pyasic.settings import PyasicSettings
|
||||
|
||||
|
||||
class CGMinerInnosiliconT3HPlus(CGMiner, InnosiliconT3HPlus):
|
||||
|
||||
@@ -12,38 +12,32 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from typing import Tuple, List, Union
|
||||
from collections.abc import AsyncIterable
|
||||
from pyasic.miners.base import AnyMiner
|
||||
import httpx
|
||||
|
||||
from pyasic.miners.antminer import *
|
||||
from pyasic.miners.avalonminer import *
|
||||
from pyasic.miners.whatsminer import *
|
||||
from pyasic.miners.innosilicon import *
|
||||
|
||||
from pyasic.miners._backends.cgminer import CGMiner # noqa - Ignore _module import
|
||||
from pyasic.miners._backends.bmminer import BMMiner # noqa - Ignore _module import
|
||||
from pyasic.miners._backends.bosminer import BOSMiner # noqa - Ignore _module import
|
||||
from pyasic.miners._backends.btminer import BTMiner # noqa - Ignore _module import
|
||||
from pyasic.miners._backends.bosminer_old import ( # noqa - Ignore _module import
|
||||
BOSMinerOld,
|
||||
)
|
||||
|
||||
from pyasic.miners.unknown import UnknownMiner
|
||||
|
||||
from pyasic.errors import APIError
|
||||
|
||||
from pyasic.misc import Singleton
|
||||
|
||||
import asyncio
|
||||
import ipaddress
|
||||
import json
|
||||
import logging
|
||||
|
||||
from pyasic.settings import PyasicSettings
|
||||
from collections.abc import AsyncIterable
|
||||
from typing import List, Tuple, Union
|
||||
|
||||
import asyncssh
|
||||
import httpx
|
||||
|
||||
from pyasic.errors import APIError
|
||||
from pyasic.miners._backends.bmminer import BMMiner # noqa - Ignore _module import
|
||||
from pyasic.miners._backends.bosminer import BOSMiner # noqa - Ignore _module import
|
||||
from pyasic.miners._backends.bosminer_old import ( # noqa - Ignore _module import
|
||||
BOSMinerOld,
|
||||
)
|
||||
from pyasic.miners._backends.btminer import BTMiner # noqa - Ignore _module import
|
||||
from pyasic.miners._backends.cgminer import CGMiner # noqa - Ignore _module import
|
||||
from pyasic.miners.antminer import *
|
||||
from pyasic.miners.avalonminer import *
|
||||
from pyasic.miners.base import AnyMiner
|
||||
from pyasic.miners.innosilicon import *
|
||||
from pyasic.miners.unknown import UnknownMiner
|
||||
from pyasic.miners.whatsminer import *
|
||||
from pyasic.misc import Singleton
|
||||
from pyasic.settings import PyasicSettings
|
||||
|
||||
MINER_CLASSES = {
|
||||
"ANTMINER S9": {
|
||||
@@ -343,7 +337,6 @@ class MinerFactory(metaclass=Singleton):
|
||||
break
|
||||
except asyncio.TimeoutError:
|
||||
logging.warning(f"{ip}: Get Miner Timed Out")
|
||||
|
||||
miner = self._select_miner_from_classes(ip, model, api, ver)
|
||||
|
||||
# save the miner to the cache at its IP if its not unknown
|
||||
@@ -439,6 +432,15 @@ class MinerFactory(metaclass=Singleton):
|
||||
|
||||
# if we have devdetails, we can get model data from there
|
||||
if devdetails:
|
||||
try:
|
||||
if devdetails[0]["STATUS"][0]["Msg"]:
|
||||
model = await self.__get_model_from_graphql(ip)
|
||||
if model:
|
||||
api = "BOSMiner+"
|
||||
return model, api, ver
|
||||
except (KeyError, TypeError, ValueError, IndexError):
|
||||
pass
|
||||
|
||||
for _devdetails_key in ["Model", "Driver"]:
|
||||
try:
|
||||
model = devdetails["DEVDETAILS"][0][_devdetails_key].upper()
|
||||
@@ -455,6 +457,14 @@ class MinerFactory(metaclass=Singleton):
|
||||
|
||||
# if we have version we can get API type from here
|
||||
if version:
|
||||
try:
|
||||
if version[0]["STATUS"][0]["Msg"]:
|
||||
model = await self.__get_model_from_graphql(ip)
|
||||
if model:
|
||||
api = "BOSMiner+"
|
||||
return model, api, ver
|
||||
except (KeyError, TypeError, ValueError, IndexError):
|
||||
pass
|
||||
if "VERSION" in version:
|
||||
api_types = ["BMMiner", "CGMiner", "BTMiner"]
|
||||
# check basic API types, BOSMiner needs a special check
|
||||
@@ -470,6 +480,8 @@ class MinerFactory(metaclass=Singleton):
|
||||
api = "BOSMiner+"
|
||||
if "BOSminer+" in version["VERSION"][0]:
|
||||
api = "BOSMiner+"
|
||||
if any("BOSer" in string for string in version["VERSION"][0]):
|
||||
api = "BOSMiner+"
|
||||
|
||||
# check for avalonminers
|
||||
for _version_key in ["PROD", "MODEL"]:
|
||||
@@ -546,6 +558,11 @@ class MinerFactory(metaclass=Singleton):
|
||||
# validate success
|
||||
validation = await self._validate_command(data)
|
||||
if not validation[0]:
|
||||
try:
|
||||
if data["version"][0]["STATUS"][0]["Msg"] == "Disconnected":
|
||||
return data["devdetails"], data["version"]
|
||||
except KeyError:
|
||||
pass
|
||||
raise APIError(validation[1])
|
||||
# copy each part of the main command to devdetails and version
|
||||
devdetails = data["devdetails"][0]
|
||||
@@ -593,6 +610,16 @@ class MinerFactory(metaclass=Singleton):
|
||||
model = "ANTMINER S17"
|
||||
return model
|
||||
|
||||
@staticmethod
|
||||
async def __get_model_from_graphql(ip: ipaddress.ip_address) -> Union[str, None]:
|
||||
model = None
|
||||
url = f"http://{ip}/graphql"
|
||||
async with httpx.AsyncClient() as client:
|
||||
d = await client.post(url, json={"query": "{bosminer {info{modelName}}}"})
|
||||
if d.status_code == 200:
|
||||
model = (d.json()["data"]["bosminer"]["info"]["modelName"]).upper()
|
||||
return model
|
||||
|
||||
@staticmethod
|
||||
async def __get_system_info_from_web(ip) -> dict:
|
||||
url = f"http://{ip}/cgi-bin/get_system_info.cgi"
|
||||
|
||||
@@ -15,10 +15,10 @@
|
||||
from typing import List
|
||||
|
||||
from pyasic.API.unknown import UnknownAPI
|
||||
from pyasic.miners.base import BaseMiner
|
||||
from pyasic.config import MinerConfig
|
||||
from pyasic.data import MinerData
|
||||
from pyasic.data.error_codes import MinerErrorData
|
||||
from pyasic.miners.base import BaseMiner
|
||||
|
||||
|
||||
class UnknownMiner(BaseMiner):
|
||||
|
||||
@@ -13,10 +13,7 @@
|
||||
# limitations under the License.
|
||||
|
||||
from pyasic.miners._backends import BTMiner # noqa - Ignore access to _module
|
||||
from pyasic.miners._types import ( # noqa - Ignore access to _module
|
||||
M20,
|
||||
M20V10,
|
||||
)
|
||||
from pyasic.miners._types import M20, M20V10 # noqa - Ignore access to _module
|
||||
|
||||
|
||||
class BTMinerM20(BTMiner, M20):
|
||||
|
||||
@@ -13,11 +13,11 @@
|
||||
# limitations under the License.
|
||||
|
||||
from pyasic.miners._backends import BTMiner # noqa - Ignore access to _module
|
||||
from pyasic.miners._types import (
|
||||
from pyasic.miners._types import ( # noqa - Ignore access to _module
|
||||
M21S,
|
||||
M21SV20,
|
||||
M21SV60,
|
||||
) # noqa - Ignore access to _module
|
||||
)
|
||||
|
||||
|
||||
class BTMinerM21S(BTMiner, M21S):
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
from .M20 import BTMinerM20, BTMinerM20V10
|
||||
from .M20S import BTMinerM20S, BTMinerM20SV10, BTMinerM20SV20
|
||||
from .M20S_Plus import BTMinerM20SPlus
|
||||
|
||||
from .M21 import BTMinerM21
|
||||
from .M21S import BTMinerM21S, BTMinerM21SV20, BTMinerM21SV60
|
||||
from .M21S_Plus import BTMinerM21SPlus
|
||||
|
||||
@@ -13,13 +13,13 @@
|
||||
# limitations under the License.
|
||||
|
||||
from pyasic.miners._backends import BTMiner # noqa - Ignore access to _module
|
||||
from pyasic.miners._types import (
|
||||
from pyasic.miners._types import ( # noqa - Ignore access to _module
|
||||
M30S,
|
||||
M30SV50,
|
||||
M30SVG20,
|
||||
M30SVE20,
|
||||
M30SVE10,
|
||||
) # noqa - Ignore access to _module
|
||||
M30SVE20,
|
||||
M30SVG20,
|
||||
)
|
||||
|
||||
|
||||
class BTMinerM30S(BTMiner, M30S):
|
||||
|
||||
@@ -13,12 +13,12 @@
|
||||
# limitations under the License.
|
||||
|
||||
from pyasic.miners._backends import BTMiner # noqa - Ignore access to _module
|
||||
from pyasic.miners._types import (
|
||||
from pyasic.miners._types import ( # noqa - Ignore access to _module
|
||||
M30SPlus,
|
||||
M30SPlusVE40,
|
||||
M30SPlusVF20,
|
||||
M30SPlusVG60,
|
||||
) # noqa - Ignore access to _module
|
||||
)
|
||||
|
||||
|
||||
class BTMinerM30SPlus(BTMiner, M30SPlus):
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
from pyasic.miners._backends import BTMiner # noqa - Ignore access to _module
|
||||
from pyasic.miners._types import ( # noqa - Ignore access to _module
|
||||
M30SPlusPlus,
|
||||
M30SPlusPlusVG40,
|
||||
M30SPlusPlusVG30,
|
||||
M30SPlusPlusVG40,
|
||||
M30SPlusPlusVH60,
|
||||
)
|
||||
|
||||
|
||||
@@ -13,15 +13,15 @@
|
||||
# limitations under the License.
|
||||
|
||||
from pyasic.miners._backends import BTMiner # noqa - Ignore access to _module
|
||||
from pyasic.miners._types import (
|
||||
from pyasic.miners._types import ( # noqa - Ignore access to _module
|
||||
M31SPlus,
|
||||
M31SPlusVE20,
|
||||
M31SPlusV30,
|
||||
M31SPlusV40,
|
||||
M31SPlusV60,
|
||||
M31SPlusV80,
|
||||
M31SPlusV90,
|
||||
) # noqa - Ignore access to _module
|
||||
M31SPlusVE20,
|
||||
)
|
||||
|
||||
|
||||
class BTMinerM31SPlus(BTMiner, M31SPlus):
|
||||
|
||||
@@ -13,9 +13,7 @@
|
||||
# limitations under the License.
|
||||
|
||||
from pyasic.miners._backends import BTMiner # noqa - Ignore access to _module
|
||||
from pyasic.miners._types import (
|
||||
M32S,
|
||||
) # noqa - Ignore access to _module
|
||||
from pyasic.miners._types import M32S # noqa - Ignore access to _module
|
||||
|
||||
|
||||
class BTMinerM32S(BTMiner, M32S):
|
||||
|
||||
@@ -13,10 +13,10 @@
|
||||
# limitations under the License.
|
||||
|
||||
from pyasic.miners._backends import BTMiner # noqa - Ignore access to _module
|
||||
from pyasic.miners._types import (
|
||||
from pyasic.miners._types import ( # noqa - Ignore access to _module
|
||||
M34SPlus,
|
||||
M34SPlusVE10,
|
||||
) # noqa - Ignore access to _module
|
||||
)
|
||||
|
||||
|
||||
class BTMinerM34SPlus(BTMiner, M34SPlus):
|
||||
|
||||
@@ -14,35 +14,33 @@
|
||||
|
||||
from .M30S import (
|
||||
BTMinerM30S,
|
||||
BTMinerM30SV50,
|
||||
BTMinerM30SVE10,
|
||||
BTMinerM30SVE20,
|
||||
BTMinerM30SVG20,
|
||||
BTMinerM30SV50,
|
||||
)
|
||||
from .M30S_Plus import (
|
||||
BTMinerM30SPlus,
|
||||
BTMinerM30SPlusVF20,
|
||||
BTMinerM30SPlusVE40,
|
||||
BTMinerM30SPlusVF20,
|
||||
BTMinerM30SPlusVG60,
|
||||
)
|
||||
from .M30S_Plus_Plus import (
|
||||
BTMinerM30SPlusPlus,
|
||||
BTMinerM30SPlusPlusVG40,
|
||||
BTMinerM30SPlusPlusVG30,
|
||||
BTMinerM30SPlusPlusVG40,
|
||||
BTMinerM30SPlusPlusVH60,
|
||||
)
|
||||
|
||||
from .M31S import BTMinerM31S
|
||||
from .M31S_Plus import (
|
||||
BTMinerM31SPlus,
|
||||
BTMinerM31SPlusVE20,
|
||||
BTMinerM31SPlusV30,
|
||||
BTMinerM31SPlusV40,
|
||||
BTMinerM31SPlusV60,
|
||||
BTMinerM31SPlusV80,
|
||||
BTMinerM31SPlusV90,
|
||||
BTMinerM31SPlusVE20,
|
||||
)
|
||||
|
||||
from .M32 import BTMinerM32, BTMinerM32V20
|
||||
from .M32S import BTMinerM32S
|
||||
from .M34S_Plus import BTMinerM34SPlus, BTMinerM34SPlusVE10
|
||||
|
||||
@@ -12,7 +12,4 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from .M50 import (
|
||||
BTMinerM50,
|
||||
BTMinerM50VH50,
|
||||
)
|
||||
from .M50 import BTMinerM50, BTMinerM50VH50
|
||||
|
||||
@@ -12,13 +12,13 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import ipaddress
|
||||
import asyncio
|
||||
import ipaddress
|
||||
import logging
|
||||
from typing import Union, List, AsyncIterator
|
||||
from typing import AsyncIterator, List, Union
|
||||
|
||||
from pyasic.miners.miner_factory import AnyMiner, MinerFactory
|
||||
from pyasic.network.net_range import MinerNetworkRange
|
||||
from pyasic.miners.miner_factory import MinerFactory, AnyMiner
|
||||
from pyasic.settings import PyasicSettings
|
||||
|
||||
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from typing import Union
|
||||
import ipaddress
|
||||
from typing import Union
|
||||
|
||||
|
||||
class MinerNetworkRange:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[tool.poetry]
|
||||
name = "pyasic"
|
||||
version = "0.20.1"
|
||||
version = "0.21.9"
|
||||
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"
|
||||
@@ -20,6 +20,7 @@ optional = true
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
pre-commit = "^2.20.0"
|
||||
isort = "^5.10.1"
|
||||
|
||||
[tool.poetry.group.docs]
|
||||
optional = true
|
||||
@@ -32,3 +33,6 @@ mkdocstrings = {extras = ["python"], version = "^0.19.0"}
|
||||
[build-system]
|
||||
requires = ["poetry-core>=1.0.0"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
|
||||
[tool.isort]
|
||||
profile = "black"
|
||||
|
||||
@@ -13,9 +13,10 @@
|
||||
# limitations under the License.
|
||||
|
||||
import unittest
|
||||
from tests.miners_tests import MinersTest, MinerFactoryTest
|
||||
from tests.network_tests import NetworkTest
|
||||
|
||||
from tests.config_tests import ConfigTest
|
||||
from tests.miners_tests import MinerFactoryTest, MinersTest
|
||||
from tests.network_tests import NetworkTest
|
||||
|
||||
if __name__ == "__main__":
|
||||
# `coverage run --source pyasic -m unittest discover` will give code coverage data
|
||||
|
||||
@@ -13,14 +13,15 @@
|
||||
# limitations under the License.
|
||||
import unittest
|
||||
|
||||
from pyasic.config import MinerConfig, _PoolGroup, _Pool # noqa
|
||||
from tests.test_data import (
|
||||
bosminer_api_pools,
|
||||
bosminer_config_pools,
|
||||
x19_api_pools,
|
||||
x19_web_pools,
|
||||
bosminer_config_pools,
|
||||
)
|
||||
|
||||
from pyasic.config import MinerConfig, _Pool, _PoolGroup # noqa
|
||||
|
||||
|
||||
class ConfigTest(unittest.TestCase):
|
||||
def setUp(self) -> None:
|
||||
|
||||
@@ -11,18 +11,15 @@
|
||||
# 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 unittest
|
||||
|
||||
from pyasic.miners.miner_factory import MINER_CLASSES
|
||||
from pyasic.miners.base import BaseMiner
|
||||
from pyasic.miners._backends import CGMiner
|
||||
from pyasic.miners.miner_factory import MinerFactory
|
||||
from pyasic.miners.miner_listener import MinerListener
|
||||
|
||||
import asyncio
|
||||
|
||||
import inspect
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
from pyasic.miners._backends import CGMiner
|
||||
from pyasic.miners.base import BaseMiner
|
||||
from pyasic.miners.miner_factory import MINER_CLASSES, MinerFactory
|
||||
from pyasic.miners.miner_listener import MinerListener
|
||||
|
||||
|
||||
class MinersTest(unittest.TestCase):
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
import ipaddress
|
||||
import unittest
|
||||
|
||||
from pyasic.network.net_range import MinerNetworkRange
|
||||
from pyasic.network import MinerNetwork
|
||||
from pyasic.network.net_range import MinerNetworkRange
|
||||
|
||||
|
||||
class NetworkTest(unittest.TestCase):
|
||||
|
||||
Reference in New Issue
Block a user