feature: add support for S19kProNoPIC BOS. Reformat.

This commit is contained in:
Upstream Data
2023-12-16 10:54:51 -07:00
parent 201cfd7ef9
commit 4459de2260
29 changed files with 144 additions and 180 deletions

View File

@@ -213,11 +213,11 @@ If you are sure you want to use this command please use API.send_command("{comma
# append that data if there is more, and then onto the main loop.
# the password timeout might need to be longer than 1, but it seems to work for now.
ret_data = await asyncio.wait_for(reader.read(1), timeout=1)
except (asyncio.TimeoutError):
except asyncio.TimeoutError:
return b"{}"
try:
ret_data += await asyncio.wait_for(reader.read(4096), timeout=timeout)
except (ConnectionAbortedError):
except ConnectionAbortedError:
return b"{}"
# loop to receive all the data

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import BOSMiner
from pyasic.miners.types import S19, S19j, S19jNoPIC, S19jPro, S19Pro
from pyasic.miners.types import S19, S19j, S19jNoPIC, S19jPro, S19kProNoPIC, S19Pro
class BOSMinerS19(BOSMiner, S19):
@@ -36,3 +36,7 @@ class BOSMinerS19jNoPIC(BOSMiner, S19jNoPIC):
class BOSMinerS19jPro(BOSMiner, S19jPro):
pass
class BOSMinerS19kProNoPIC(BOSMiner, S19kProNoPIC):
pass

View File

@@ -19,6 +19,7 @@ from .S19 import (
BOSMinerS19j,
BOSMinerS19jNoPIC,
BOSMinerS19jPro,
BOSMinerS19kProNoPIC,
BOSMinerS19Pro,
)
from .T19 import BOSMinerT19

View File

@@ -15,34 +15,32 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import ePIC
from pyasic.miners.types import (
S19,
S19Pro,
S19j,
S19jPro,
S19jProPlus,
S19kPro,
S19XP,
)
from pyasic.miners.types import S19, S19XP, S19j, S19jPro, S19jProPlus, S19kPro, S19Pro
class ePICS19(ePIC, S19):
pass
class ePICS19Pro(ePIC, S19Pro):
pass
class ePICS19j(ePIC, S19j):
pass
class ePICS19jPro(ePIC, S19jPro):
pass
class ePICS19jProPlus(ePIC, S19jProPlus):
pass
class ePICS19kPro(ePIC, S19kPro):
pass
class ePICS19XP(ePIC, S19XP):
pass

View File

@@ -557,7 +557,6 @@ class BOSMiner(BaseMiner):
async def get_hashrate(
self, api_summary: dict = None, graphql_hashrate: dict = None
) -> Optional[float]:
# get hr from graphql
if not graphql_hashrate:
try:

View File

@@ -260,8 +260,6 @@ class BTMiner(BaseMiner):
self.config = cfg
return self.config
async def set_power_limit(self, wattage: int) -> bool:
try:
await self.api.adjust_power_limit(wattage)
@@ -411,7 +409,6 @@ class BTMiner(BaseMiner):
pass
async def get_hashboards(self, api_devs: dict = None) -> List[HashBoard]:
hashboards = [
HashBoard(slot=i, expected_chips=self.nominal_chips)
for i in range(self.ideal_hashboards)

View File

@@ -14,16 +14,14 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
from typing import Optional
from typing import List, Optional, Tuple, Union
from pyasic.data import Fan, HashBoard
from pyasic.data.error_codes import MinerErrorData, X19Error
from pyasic.errors import APIError
from pyasic.logger import logger
from pyasic.miners.backends.bmminer import BMMiner
from pyasic.web.epic import ePICWebAPI
from pyasic.data import Fan, HashBoard
from typing import List, Optional, Tuple, Union
from pyasic.data.error_codes import MinerErrorData, X19Error
EPIC_DATA_LOC = {
"mac": {"cmd": "get_mac", "kwargs": {"web_summary": {"web": "network"}}},
@@ -36,12 +34,21 @@ EPIC_DATA_LOC = {
"cmd": "get_nominal_hashrate",
"kwargs": {"web_summary": {"web": "summary"}},
},
"hashboards": {"cmd": "get_hashboards", "kwargs": {"web_summary": {"web": "summary"}, "web_hashrate": {"web": "hashrate"}}},
"hashboards": {
"cmd": "get_hashboards",
"kwargs": {
"web_summary": {"web": "summary"},
"web_hashrate": {"web": "hashrate"},
},
},
"env_temp": {"cmd": "get_env_temp", "kwargs": {}},
"wattage": {"cmd": "get_wattage", "kwargs": {"web_summary": {"web": "summary"}}},
"fans": {"cmd": "get_fans", "kwargs": {"web_summary": {"web": "summary"}}},
"fan_psu": {"cmd": "get_fan_psu", "kwargs": {}},
"fault_light": {"cmd": "get_fault_light", "kwargs": {"web_summary": {"web": "summary"}}},
"fault_light": {
"cmd": "get_fault_light",
"kwargs": {"web_summary": {"web": "summary"}},
},
"pools": {"cmd": "get_pools", "kwargs": {"web_summary": {"web": "summary"}}},
"is_mining": {"cmd": "is_mining", "kwargs": {}},
"uptime": {"cmd": "get_uptime", "kwargs": {"web_summary": {"web": "summary"}}},
@@ -148,12 +155,11 @@ class ePIC(BMMiner):
if web_summary["HBs"] != None:
for hb in web_summary["HBs"]:
hashrate += hb["Hashrate"][0]
return round(
float(float(hashrate/ 1000000)), 2)
return round(float(float(hashrate / 1000000)), 2)
except (LookupError, ValueError, TypeError) as e:
logger.error(e)
pass
async def get_nominal_hashrate(self, web_summary: dict = None) -> Optional[float]:
# get hr from API
if not web_summary:
@@ -170,16 +176,14 @@ class ePIC(BMMiner):
if hb["Hashrate"][1] == 0:
ideal = 1.0
else:
ideal = hb["Hashrate"][1]/100
hashrate += hb["Hashrate"][0]/ideal
return round(
float(float(hashrate/ 1000000)), 2)
ideal = hb["Hashrate"][1] / 100
hashrate += hb["Hashrate"][0] / ideal
return round(float(float(hashrate / 1000000)), 2)
except (IndexError, KeyError, ValueError, TypeError) as e:
logger.error(e)
pass
async def get_fw_ver(self, web_summary: dict = None) -> Optional[str]:
if not web_summary:
web_summary = await self.web.summary()
@@ -208,8 +212,10 @@ class ePIC(BMMiner):
except (LookupError, ValueError, TypeError):
fans.append(Fan())
return fans
async def get_hashboards(self, web_summary: dict = None, web_hashrate: dict= None) -> List[HashBoard]:
async def get_hashboards(
self, web_summary: dict = None, web_hashrate: dict = None
) -> List[HashBoard]:
if not web_summary:
try:
web_summary = await self.web.summary()
@@ -220,51 +226,53 @@ class ePIC(BMMiner):
web_hashrate = await self.web.hashrate()
except APIError:
pass
hb_list = [HashBoard(slot=i, expected_chips=self.nominal_chips) for i in range(self.ideal_hashboards)]
hb_list = [
HashBoard(slot=i, expected_chips=self.nominal_chips)
for i in range(self.ideal_hashboards)
]
if web_summary["HBs"] != None:
for hb in web_summary["HBs"]:
for hr in web_hashrate:
if hr["Index"] == hb["Index"]:
num_of_chips = len(hr["Data"])
hashrate = hb["Hashrate"][0]
#Update the Hashboard object
# Update the Hashboard object
hb_list[hr["Index"]].expected_chips = num_of_chips
hb_list[hr["Index"]].missing = False
hb_list[hr["Index"]].hashrate = round(hashrate/1000000,2)
hb_list[hr["Index"]].hashrate = round(hashrate / 1000000, 2)
hb_list[hr["Index"]].chips = num_of_chips
hb_list[hr["Index"]].temp = hb["Temperature"]
return hb_list
async def is_mining(self, *args, **kwargs) -> Optional[bool]:
return None
async def get_pools(self, web_summary: dict = None) -> List[dict]:
groups = []
groups = []
if not web_summary:
try:
web_summary = await self.api.summary()
except APIError:
pass
if not web_summary:
try:
web_summary = await self.api.summary()
except APIError:
pass
if web_summary:
try:
pools = {}
for i, pool in enumerate(web_summary["StratumConfigs"]):
pools[f"pool_{i + 1}_url"] = (
pool["pool"]
.replace("stratum+tcp://", "")
.replace("stratum2+tcp://", "")
)
pools[f"pool_{i + 1}_user"] = pool["login"]
pools["quota"] = pool["Quota"] if pool.get("Quota") else "0"
if web_summary:
try:
pools = {}
for i, pool in enumerate(web_summary["StratumConfigs"]):
pools[f"pool_{i + 1}_url"] = (
pool["pool"]
.replace("stratum+tcp://", "")
.replace("stratum2+tcp://", "")
)
pools[f"pool_{i + 1}_user"] = pool["login"]
pools["quota"] = pool["Quota"] if pool.get("Quota") else "0"
groups.append(pools)
except KeyError:
pass
return groups
groups.append(pools)
except KeyError:
pass
return groups
async def get_uptime(self, web_summary: dict = None) -> Optional[int]:
if not web_summary:
web_summary = await self.web.summary()
@@ -275,7 +283,7 @@ class ePIC(BMMiner):
except KeyError:
pass
return None
async def get_fault_light(self, web_summary: dict = None) -> bool:
if not web_summary:
web_summary = await self.web.summary()
@@ -286,7 +294,7 @@ class ePIC(BMMiner):
except KeyError:
pass
return False
async def get_errors(self, web_summary: dict = None) -> List[MinerErrorData]:
if not web_summary:
web_summary = await self.web.summary()

View File

@@ -352,6 +352,7 @@ MINER_CLASSES = {
"ANTMINER S19J PRO": BOSMinerS19jPro,
"ANTMINER S19J PRO NOPIC": BOSMinerS19jPro,
"ANTMINER T19": BOSMinerT19,
"ANTMINER S19K PRO NOPIC": BOSMinerS19kProNoPIC,
},
MinerTypes.VNISH: {
None: VNish,

View File

@@ -124,6 +124,7 @@ class S19jPro(AntMiner): # noqa - ignore ABC method implementation
self.nominal_chips = 126
self.fan_count = 4
class S19jProPlus(AntMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
@@ -132,6 +133,7 @@ class S19jProPlus(AntMiner): # noqa - ignore ABC method implementation
self.nominal_chips = 120
self.fan_count = 4
class S19kPro(AntMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
@@ -148,3 +150,12 @@ class S19L(AntMiner): # noqa - ignore ABC method implementation
self.model = "S19L"
self.nominal_chips = 76
self.fan_count = 4
class S19kProNoPIC(AntMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "S19k Pro No PIC"
self.nominal_chips = 77
self.fan_count = 4

View File

@@ -26,6 +26,7 @@ from .S19 import (
S19jPro,
S19jProPlus,
S19kPro,
S19kProNoPIC,
S19NoPIC,
S19Plus,
S19Pro,

View File

@@ -213,6 +213,7 @@ class M30SPlusVF30(WhatsMiner): # noqa - ignore ABC method implementation
self.nominal_chips = 117
self.fan_count = 2
class M30SPlusVG20(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
@@ -221,6 +222,7 @@ class M30SPlusVG20(WhatsMiner): # noqa - ignore ABC method implementation
self.nominal_chips = 82
self.fan_count = 2
class M30SPlusVG30(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)

View File

@@ -18,6 +18,7 @@ import warnings
from pyasic.miners.makes import WhatsMiner
class M31HV10(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
@@ -26,6 +27,7 @@ class M31HV10(WhatsMiner): # noqa - ignore ABC method implementation
self.nominal_chips = 114
self.fan_count = 0
class M31HV40(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)

View File

@@ -18,6 +18,7 @@ import warnings
from pyasic.miners.makes import WhatsMiner
class M31LV10(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)

View File

@@ -18,6 +18,7 @@ import warnings
from pyasic.miners.makes import WhatsMiner
class M33SPlusVG20(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
@@ -44,7 +45,7 @@ class M33SPlusVH30(WhatsMiner): # noqa - ignore ABC method implementation
self.ip = ip
self.model = "M33S+ VH30"
self.ideal_hashboards = 4
self.nominal_chips = 0 # slot1 116, slot2 106, slot3 116, slot4 106
self.nominal_chips = 0 # slot1 116, slot2 106, slot3 116, slot4 106
warnings.warn(
"Unknown chip count for miner type M30S+ VH30, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
)

View File

@@ -18,6 +18,7 @@ import warnings
from pyasic.miners.makes import WhatsMiner
class M39V10(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)

View File

@@ -18,6 +18,7 @@ import warnings
from pyasic.miners.makes import WhatsMiner
class M50VE30(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
@@ -27,6 +28,7 @@ class M50VE30(WhatsMiner): # noqa - ignore ABC method implementation
self.nominal_chips = 255
self.fan_count = 2
class M50VG30(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)

View File

@@ -13,11 +13,12 @@
# See the License for the specific language governing permissions and -
# limitations under the License. -
# ------------------------------------------------------------------------------
import warnings
from pyasic.miners.makes import WhatsMiner
class M60VK10(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
@@ -63,4 +64,4 @@ class M60VK40(WhatsMiner): # noqa - ignore ABC method implementation
warnings.warn(
"Unknown chip count for miner type M60 VK40, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
)
self.fan_count = 2
self.fan_count = 2

View File

@@ -13,11 +13,12 @@
# See the License for the specific language governing permissions and -
# limitations under the License. -
# ------------------------------------------------------------------------------
import warnings
from pyasic.miners.makes import WhatsMiner
class M60SVK10(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
@@ -61,4 +62,4 @@ class M60SVK40(WhatsMiner): # noqa - ignore ABC method implementation
warnings.warn(
"Unknown chip count for miner type M60S VK40, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
)
self.fan_count = 2
self.fan_count = 2

View File

@@ -13,11 +13,12 @@
# See the License for the specific language governing permissions and -
# limitations under the License. -
# ------------------------------------------------------------------------------
import warnings
from pyasic.miners.makes import WhatsMiner
class M63VK10(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
@@ -49,4 +50,4 @@ class M63VK30(WhatsMiner): # noqa - ignore ABC method implementation
self.model = "M63 VK30"
self.nominal_chips = 68
self.ideal_hashboards = 4
self.fan_count = 0
self.fan_count = 0

View File

@@ -13,11 +13,12 @@
# See the License for the specific language governing permissions and -
# limitations under the License. -
# ------------------------------------------------------------------------------
import warnings
from pyasic.miners.makes import WhatsMiner
class M63SVK10(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
@@ -51,4 +52,4 @@ class M63SVK30(WhatsMiner): # noqa - ignore ABC method implementation
warnings.warn(
"Unknown chip count for miner type M63S VK30, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
)
self.fan_count = 0
self.fan_count = 0

View File

@@ -13,7 +13,7 @@
# See the License for the specific language governing permissions and -
# limitations under the License. -
# ------------------------------------------------------------------------------
import warnings
from pyasic.miners.makes import WhatsMiner
@@ -40,4 +40,4 @@ class M66VK30(WhatsMiner): # noqa - ignore ABC method implementation
warnings.warn(
"Unknown chip count for miner type M66 VK30, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
)
self.fan_count = 0
self.fan_count = 0

View File

@@ -50,4 +50,4 @@ class M66SVK40(WhatsMiner): # noqa - ignore ABC method implementation
warnings.warn(
"Unknown chip count for miner type M66 VK30, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
)
self.fan_count = 0
self.fan_count = 0

View File

@@ -14,39 +14,9 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
from .M60 import (
M60VK10,
M60VK20,
M60VK30,
M60VK40,
)
from .M60S import (
M60SVK10,
M60SVK20,
M60SVK30,
M60SVK40,
)
from .M63 import (
M63VK10,
M63VK20,
M63VK30,
)
from .M63S import (
M63SVK10,
M63SVK20,
M63SVK30,
)
from .M66 import (
M66VK20,
M66VK30,
)
from .M66S import (
M66SVK20,
M66SVK30,
M66SVK40,
)
from .M60 import M60VK10, M60VK20, M60VK30, M60VK40
from .M60S import M60SVK10, M60SVK20, M60SVK30, M60SVK40
from .M63 import M63VK10, M63VK20, M63VK30
from .M63S import M63SVK10, M63SVK20, M63SVK30
from .M66 import M66VK20, M66VK30
from .M66S import M66SVK20, M66SVK30, M66SVK40

View File

@@ -15,12 +15,7 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import M6X
from pyasic.miners.types import (
M60VK10,
M60VK20,
M60VK30,
M60VK40,
)
from pyasic.miners.types import M60VK10, M60VK20, M60VK30, M60VK40
class BTMinerM60VK10(M6X, M60VK10):

View File

@@ -15,12 +15,7 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import M6X
from pyasic.miners.types import (
M60SVK10,
M60SVK20,
M60SVK30,
M60SVK40,
)
from pyasic.miners.types import M60SVK10, M60SVK20, M60SVK30, M60SVK40
class BTMinerM60SVK10(M6X, M60SVK10):

View File

@@ -15,11 +15,7 @@
# ------------------------------------------------------------------------------
from pyasic.miners.backends import M6X
from pyasic.miners.types import (
M66SVK20,
M66SVK30,
M66SVK40,
)
from pyasic.miners.types import M66SVK20, M66SVK30, M66SVK40
class BTMinerM66SVK20(M6X, M66SVK20):
@@ -31,4 +27,4 @@ class BTMinerM66SVK30(M6X, M66SVK30):
class BTMinerM66SVK40(M6X, M66SVK40):
pass
pass

View File

@@ -14,39 +14,9 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
from .M60 import (
BTMinerM60VK10,
BTMinerM60VK20,
BTMinerM60VK30,
BTMinerM60VK40,
)
from .M60S import (
BTMinerM60SVK10,
BTMinerM60SVK20,
BTMinerM60SVK30,
BTMinerM60SVK40,
)
from .M63 import (
BTMinerM63VK10,
BTMinerM63VK20,
BTMinerM63VK30,
)
from .M63S import (
BTMinerM63SVK10,
BTMinerM63SVK20,
BTMinerM63SVK30,
)
from .M66 import (
BTMinerM66VK20,
BTMinerM66VK30,
)
from .M66S import (
BTMinerM66SVK20,
BTMinerM66SVK30,
BTMinerM66SVK40,
)
from .M60 import BTMinerM60VK10, BTMinerM60VK20, BTMinerM60VK30, BTMinerM60VK40
from .M60S import BTMinerM60SVK10, BTMinerM60SVK20, BTMinerM60SVK30, BTMinerM60SVK40
from .M63 import BTMinerM63VK10, BTMinerM63VK20, BTMinerM63VK30
from .M63S import BTMinerM63SVK10, BTMinerM63SVK20, BTMinerM63SVK30
from .M66 import BTMinerM66VK20, BTMinerM66VK30
from .M66S import BTMinerM66SVK20, BTMinerM66SVK30, BTMinerM66SVK40

View File

@@ -17,4 +17,4 @@
from .M2X import *
from .M3X import *
from .M5X import *
from .M6X import *
from .M6X import *

View File

@@ -20,8 +20,9 @@ from typing import Union
import httpx
from pyasic import settings
from pyasic.web import BaseWebAPI
from pyasic.errors import APIError, APIWarning
from pyasic.web import BaseWebAPI
class ePICWebAPI(BaseWebAPI):
def __init__(self, ip: str) -> None:
@@ -31,22 +32,24 @@ class ePICWebAPI(BaseWebAPI):
self.token = None
async def send_command(
self,
command: Union[str, bytes],
ignore_errors: bool = False,
allow_warning: bool = True,
post: bool = False,
**parameters: Union[str, int, bool],
self,
command: Union[str, bytes],
ignore_errors: bool = False,
allow_warning: bool = True,
post: bool = False,
**parameters: Union[str, int, bool],
) -> dict:
if post or parameters != {}:
post = True
async with httpx.AsyncClient(transport=settings.transport()) as client:
for i in range(settings.get("get_data_retries", 1) + 1):
try:
if post:
epic_param = {"param": parameters.get("parameters"),
"password": self.pwd}
epic_param = {
"param": parameters.get("parameters"),
"password": self.pwd,
}
response = await client.post(
f"http://{self.ip}:4028/{command}",
timeout=5,
@@ -56,14 +59,17 @@ class ePICWebAPI(BaseWebAPI):
response = await client.get(
f"http://{self.ip}:4028/{command}",
timeout=5,
)
if not response.status_code == 200:
continue
json_data = response.json()
if json_data:
# The API can return a fail status if the miner cannot return the requested data. Catch this and pass
if "result" in json_data and json_data["result"] is False and not post:
if (
"result" in json_data
and json_data["result"] is False
and not post
):
if not i > settings.get("get_data_retries", 1):
continue
if not ignore_errors:
@@ -102,13 +108,12 @@ class ePICWebAPI(BaseWebAPI):
async def summary(self):
return await self.send_command("summary")
async def hashrate(self):
return await self.send_command("hashrate")
async def network(self):
return await self.send_command("network")
async def capabilities(self):
return await self.send_command("capabilities")