Compare commits

...

24 Commits

Author SHA1 Message Date
UpstreamData
269b13f6c1 version: bump version number. 2023-09-15 08:57:56 -06:00
Elias Kunnas
a9bb7d2e5a Fix btminer pre_power_on (#62) 2023-09-15 08:56:29 -06:00
Upstream Data
11295f27a7 version: bump version number. 2023-09-12 19:21:04 -06:00
Upstream Data
55aa3dd85b bug: handle edge cases where a missed get_config on bosminer can cause an empty config to be applied to a miner. 2023-09-12 19:20:48 -06:00
UpstreamData
20272d4360 version: bump version number. 2023-09-11 13:45:52 -06:00
UpstreamData
623dc92ef2 feature: Add MinerData.as_dict(). 2023-09-11 13:45:23 -06:00
Upstream Data
2d59394b1e version: bump version number. 2023-09-07 19:07:11 -06:00
Upstream Data
26c2095ff1 bug: fix uncaught error in get_hashboards with BMMiner if a key doesnt exist. 2023-09-07 19:06:51 -06:00
Upstream Data
ec7d241caa version: bump version number. 2023-09-05 17:22:23 -06:00
Upstream Data
d0432ed1aa bug: handle for some weird edge cases with boards plugged into the wrong slots on X19. 2023-09-05 17:22:02 -06:00
Upstream Data
8c5503d002 version: bump version number. 2023-08-30 17:47:20 -06:00
Upstream Data
6d6f950c95 bug: add modified changed from [Issue 57](https://github.com/UpstreamData/pyasic/issues/57#issuecomment-1699984187) 2023-08-30 17:46:23 -06:00
UpstreamData
30745e54ba feature: add chip count for M30S+VE50 2023-08-30 11:18:25 -06:00
UpstreamData
c3fd94e79e version: bump version number. 2023-08-28 08:53:59 -06:00
UpstreamData
2924a8d67b feature: add more whatsminer error codes. 2023-08-28 08:53:27 -06:00
UpstreamData
9f4c4bb9cf feature: add exclude to get_data, and change data_to_get to include. 2023-08-28 08:32:29 -06:00
UpstreamData
3d6eebf06e bug: fix a bug with hostname gathering on some Avalons. 2023-08-28 08:31:54 -06:00
Upstream Data
b3d9b6ff7e version: bump version number. 2023-08-26 11:21:21 -06:00
Upstream Data
60facacc48 bug: fix a bug with bosminer commands. 2023-08-26 11:21:10 -06:00
Upstream Data
b8a6063838 version: bumnp version number. 2023-08-26 10:57:40 -06:00
Upstream Data
bcba2be524 bug: remove bad await calls to httpx response.json(). 2023-08-26 10:56:53 -06:00
UpstreamData
f7187d2017 bug: add chip count for M29V10. 2023-08-25 08:58:34 -06:00
Upstream Data
d91b7c4406 version: bump version number. 2023-08-07 17:02:50 -06:00
Upstream Data
248a7e6d69 bug: fix some WM models reporting https first and being identified as BOS+. 2023-08-07 17:02:26 -06:00
12 changed files with 348 additions and 125 deletions

View File

@@ -258,9 +258,12 @@ If you are sure you want to use this command please use API.send_command("{comma
return False, data["Msg"] return False, data["Msg"]
else: else:
# make sure the command succeeded # make sure the command succeeded
if type(data["STATUS"]) == str: if isinstance(data["STATUS"], str):
if data["STATUS"] in ["RESTART"]: if data["STATUS"] in ["RESTART"]:
return True, None return True, None
elif isinstance(data["STATUS"], dict):
if data["STATUS"].get("STATUS") in ["S", "I"]:
return True, None
elif data["STATUS"][0]["STATUS"] not in ("S", "I"): elif data["STATUS"][0]["STATUS"] not in ("S", "I"):
# this is an error # this is an error
if data["STATUS"][0]["STATUS"] not in ("S", "I"): if data["STATUS"][0]["STATUS"] not in ("S", "I"):

View File

@@ -22,7 +22,7 @@ import hashlib
import json import json
import logging import logging
import re import re
from typing import Union from typing import Literal, Union
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from passlib.handlers.md5_crypt import md5_crypt from passlib.handlers.md5_crypt import md5_crypt
@@ -40,6 +40,12 @@ from pyasic.settings import PyasicSettings
# you change the password, you can pass that to this class as pwd, # you change the password, you can pass that to this class as pwd,
# or add it as the Whatsminer_pwd in the settings.toml file. # or add it as the Whatsminer_pwd in the settings.toml file.
PrePowerOnMessage = Union[
Literal["wait for adjust temp"],
Literal["adjust complete"],
Literal["adjust continue"],
]
def _crypt(word: str, salt: str) -> str: def _crypt(word: str, salt: str) -> str:
"""Encrypts a word with a salt, using a standard salt format. """Encrypts a word with a salt, using a standard salt format.
@@ -693,7 +699,7 @@ class BTMinerAPI(BaseMinerAPI):
) )
return await self.send_privileged_command("set_power_pct", percent=str(percent)) return await self.send_privileged_command("set_power_pct", percent=str(percent))
async def pre_power_on(self, complete: bool, msg: str) -> dict: async def pre_power_on(self, complete: bool, msg: PrePowerOnMessage) -> dict:
"""Configure or check status of pre power on. """Configure or check status of pre power on.
<details> <details>
@@ -713,7 +719,7 @@ class BTMinerAPI(BaseMinerAPI):
</details> </details>
""" """
if not msg == "wait for adjust temp" or "adjust complete" or "adjust continue": if msg not in ("wait for adjust temp", "adjust complete", "adjust continue"):
raise APIError( raise APIError(
"Message is incorrect, please choose one of " "Message is incorrect, please choose one of "
'["wait for adjust temp", ' '["wait for adjust temp", '

View File

@@ -338,13 +338,16 @@ class MinerData:
pass pass
def asdict(self) -> dict: def asdict(self) -> dict:
logging.debug(f"MinerData - (To Dict) - Dumping Dict data")
return asdict(self)
def as_dict(self) -> dict:
"""Get this dataclass as a dictionary. """Get this dataclass as a dictionary.
Returns: Returns:
A dictionary version of this class. A dictionary version of this class.
""" """
logging.debug(f"MinerData - (To Dict) - Dumping Dict data") return self.asdict()
return asdict(self)
def as_json(self) -> str: def as_json(self) -> str:
"""Get this dataclass as JSON. """Get this dataclass as JSON.

View File

@@ -16,8 +16,6 @@
from dataclasses import asdict, dataclass, field, fields from dataclasses import asdict, dataclass, field, fields
C_N_CODES = ["52", "53", "54", "55", "56"]
@dataclass @dataclass
class WhatsminerError: class WhatsminerError:
@@ -37,10 +35,8 @@ class WhatsminerError:
@property @property
def error_message(self): # noqa - Skip PyCharm inspection def error_message(self): # noqa - Skip PyCharm inspection
if len(str(self.error_code)) > 3 and str(self.error_code)[:2] in C_N_CODES: if len(str(self.error_code)) == 6 and not str(self.error_code)[:1] == "1":
# 55 error code base has chip numbers, so the format is err_type = int(str(self.error_code)[:2])
# 55 -> board num len 1 -> chip num len 3
err_type = 55
err_subtype = int(str(self.error_code)[2:3]) err_subtype = int(str(self.error_code)[2:3])
err_value = int(str(self.error_code)[3:]) err_value = int(str(self.error_code)[3:])
else: else:
@@ -88,7 +84,9 @@ class WhatsminerError:
ERROR_CODES = { ERROR_CODES = {
1: { # Fan error 1: { # Fan error
0: {0: "Fan unknown."}, 0: {
0: "Fan unknown.",
},
1: { # Fan speed error of 1000+ 1: { # Fan speed error of 1000+
0: "Intake fan speed error.", 0: "Intake fan speed error.",
1: "Exhaust fan speed error.", 1: "Exhaust fan speed error.",
@@ -101,7 +99,9 @@ ERROR_CODES = {
0: "Intake fan speed error. Fan speed deviates by more than 3000.", 0: "Intake fan speed error. Fan speed deviates by more than 3000.",
1: "Exhaust fan speed error. Fan speed deviates by more than 3000.", 1: "Exhaust fan speed error. Fan speed deviates by more than 3000.",
}, },
4: {0: "Fan speed too high."}, # High speed 4: {
0: "Fan speed too high.",
}, # High speed
}, },
2: { # Power error 2: { # Power error
0: { 0: {
@@ -126,6 +126,7 @@ ERROR_CODES = {
6: "Power remained unchanged for a long time.", 6: "Power remained unchanged for a long time.",
7: "Power set enable error.", 7: "Power set enable error.",
8: "Power input voltage is lower than 230V for high power mode.", 8: "Power input voltage is lower than 230V for high power mode.",
9: "Power input current is incorrect.",
}, },
3: { 3: {
3: "Power output high temperature protection error.", 3: "Power output high temperature protection error.",
@@ -159,6 +160,8 @@ ERROR_CODES = {
6: { 6: {
3: "Power communication warning.", 3: "Power communication warning.",
4: "Power communication error.", 4: "Power communication error.",
5: "Power unknown error.",
6: "Power unknown error.",
7: "Power watchdog protection.", 7: "Power watchdog protection.",
8: "Power output high current protection.", 8: "Power output high current protection.",
9: "Power input high current protection.", 9: "Power input high current protection.",
@@ -170,57 +173,134 @@ ERROR_CODES = {
3: "Power input too high warning.", 3: "Power input too high warning.",
4: "Power fan warning.", 4: "Power fan warning.",
5: "Power high temperature warning.", 5: "Power high temperature warning.",
6: "Power unknown error.",
7: "Power unknown error.",
8: "Power unknown error.",
9: "Power unknown error.",
},
8: {
0: "Power unknown error.",
1: "Power vendor status 1 bit 0 error.",
2: "Power vendor status 1 bit 1 error.",
3: "Power vendor status 1 bit 2 error.",
4: "Power vendor status 1 bit 3 error.",
5: "Power vendor status 1 bit 4 error.",
6: "Power vendor status 1 bit 5 error.",
7: "Power vendor status 1 bit 6 error.",
8: "Power vendor status 1 bit 7 error.",
9: "Power vendor status 2 bit 0 error.",
},
9: {
0: "Power vendor status 2 bit 1 error.",
1: "Power vendor status 2 bit 2 error.",
2: "Power vendor status 2 bit 3 error.",
3: "Power vendor status 2 bit 4 error.",
4: "Power vendor status 2 bit 5 error.",
5: "Power vendor status 2 bit 6 error.",
6: "Power vendor status 2 bit 7 error.",
}, },
}, },
3: { # temperature error 3: { # temperature error
0: { # sensor detection error 0: { # sensor detection error
"n": "Slot {n} temperature sensor detection error." "n": "Slot {n} temperature sensor detection error.",
}, },
2: { # temperature reading error 2: { # temperature reading error
"n": "Slot {n} temperature reading error.", "n": "Slot {n} temperature reading error.",
9: "Control board temperature sensor communication error.", 9: "Control board temperature sensor communication error.",
}, },
5: {"n": "Slot {n} temperature protecting."}, # temperature protection 5: {
6: {0: "Hashboard high temperature error."}, # high temp "n": "Slot {n} temperature protecting.",
}, # temperature protection
6: {
0: "Hashboard high temperature error.",
1: "Hashboard high temperature error.",
2: "Hashboard high temperature error.",
3: "Hashboard high temperature error.",
}, # high temp
7: {
0: "The environment temperature fluctuates too much.",
}, # env temp
8: { 8: {
0: "Humidity sensor not found.", 0: "Humidity sensor not found.",
1: "Humidity sensor read error.", 1: "Humidity sensor read error.",
2: "Humidity sensor read error.", 2: "Humidity sensor read error.",
3: "Humidity sensor protecting.", 3: "Humidity sensor protecting.",
}, }, # humidity
}, },
4: { # EEPROM error 4: { # EEPROM error
0: {0: "Eeprom unknown error."}, 0: {
1: {"n": "Slot {n} eeprom detection error."}, # EEPROM detection error 0: "Eeprom unknown error.",
2: {"n": "Slot {n} eeprom parsing error."}, # EEPROM parsing error },
3: {"n": "Slot {n} chip bin type error."}, # chip bin error 1: {
4: {"n": "Slot {n} eeprom chip number X error."}, # EEPROM chip number error "n": "Slot {n} eeprom detection error.",
5: {"n": "Slot {n} eeprom xfer error."}, # EEPROM xfer error }, # EEPROM detection error
2: {
"n": "Slot {n} eeprom parsing error.",
}, # EEPROM parsing error
3: {
"n": "Slot {n} chip bin type error.",
}, # chip bin error
4: {
"n": "Slot {n} eeprom chip number X error.",
}, # EEPROM chip number error
5: {
"n": "Slot {n} eeprom xfer error.",
}, # EEPROM xfer error
}, },
5: { # hashboard error 5: { # hashboard error
0: {0: "Board unknown error."}, 0: {
1: {"n": "Slot {n} miner type error."}, # board miner type error 0: "Board unknown error.",
2: {"n": "Slot {n} bin type error."}, # chip bin type error },
3: {"n": "Slot {n} not found."}, # board not found error 1: {
4: {"n": "Slot {n} error reading chip id."}, # reading chip id error "n": "Slot {n} miner type error.",
5: {"n": "Slot {n} has bad chips."}, # board has bad chips error }, # board miner type error
6: {"n": "Slot {n} loss of balance error."}, # loss of balance error 2: {
7: {"n": "Slot {n} xfer error chip."}, # xfer error "n": "Slot {n} bin type error.",
8: {"n": "Slot {n} reset error."}, # reset error }, # chip bin type error
9: {"n": "Slot {n} frequency too low."}, # freq error 3: {
"n": "Slot {n} not found.",
}, # board not found error
4: {
"n": "Slot {n} error reading chip id.",
}, # reading chip id error
5: {
"n": "Slot {n} has bad chips.",
}, # board has bad chips error
6: {
"n": "Slot {n} loss of balance error.",
}, # loss of balance error
7: {
"n": "Slot {n} xfer error chip.",
}, # xfer error
8: {
"n": "Slot {n} reset error.",
}, # reset error
9: {
"n": "Slot {n} frequency too low.",
}, # freq error
}, },
6: { # env temp error 6: { # env temp error
0: {0: "Environment temperature is too high."}, # normal env temp error 0: {
0: "Environment temperature is too high.",
}, # normal env temp error
1: { # high power env temp error 1: { # high power env temp error
0: "Environment temperature is too high for high performance mode." 0: "Environment temperature is too high for high performance mode.",
}, },
}, },
7: { # control board error 7: { # control board error
0: {0: "MAC address invalid", 1: "Control board no support chip."}, 0: {
0: "MAC address invalid",
1: "Control board no support chip.",
},
1: { 1: {
0: "Control board rebooted as an exception.", 0: "Control board rebooted as an exception.",
1: "Control board rebooted as exception and cpufreq reduced, please upgrade the firmware", 1: "Control board rebooted as exception and cpufreq reduced, please upgrade the firmware",
2: "Control board rebooted as an exception.", 2: "Control board rebooted as an exception.",
3: "The network is unstable, change time.",
4: "Unknown error.",
},
2: {
"n": "Control board slot {n} frame error.",
}, },
}, },
8: { # checksum error 8: { # checksum error
@@ -228,63 +308,152 @@ ERROR_CODES = {
0: "CGMiner checksum error.", 0: "CGMiner checksum error.",
1: "System monitor checksum error.", 1: "System monitor checksum error.",
2: "Remote daemon checksum error.", 2: "Remote daemon checksum error.",
},
1: {0: "Air to liquid PCB serial # does not match."},
},
9: {
0: {0: "Unknown error.", 1: "Power rate error.", 2: "Unknown error."}
}, # power rate error
20: { # pool error
0: {
0: "No pool information configured.",
},
1: {
0: "All pools are disabled.",
}, # all disabled error
2: {
"n": "Pool {n} connection failed.",
}, # pool connection failed error
3: {
0: "High rejection rate on pool.",
}, # rejection rate error
4: { # asicboost not supported error
0: "The pool does not support asicboost mode.",
},
},
21: {
1: {
"n": "Slot {n} factory test step failed.",
} }
}, },
9: {0: {1: "Power rate error."}}, # power rate error
20: { # pool error
1: {0: "All pools are disabled."}, # all disabled error
2: {"n": "Pool {n} connection failed."}, # pool connection failed error
3: {0: "High rejection rate on pool."}, # rejection rate error
4: { # asicboost not supported error
0: "The pool does not support asicboost mode."
},
},
21: {1: {"n": "Slot {n} factory test step failed."}},
23: { # hashrate error 23: { # hashrate error
1: {0: "Hashrate is too low."}, 1: {
2: {0: "Hashrate is too low."}, 0: "Hashrate is too low.",
3: {0: "Hashrate loss is too high."}, },
4: {0: "Hashrate loss is too high."}, 2: {
5: {0: "Hashrate loss."}, 0: "Hashrate is too low.",
},
3: {
0: "Hashrate loss is too high.",
},
4: {
0: "Hashrate loss is too high.",
},
5: {
0: "Hashrate loss.",
},
}, },
50: { # water velocity error/voltage error 50: { # water velocity error/voltage error
1: {"n": "Slot {n} chip voltage too low."}, 1: {
2: {"n": "Slot {n} chip voltage changed."}, "n": "Slot {n} chip voltage too low.",
3: {"n": "Slot {n} chip temperature difference is too large."}, },
4: {"n": "Slot {n} chip hottest temperature difference is too large."}, 2: {
7: {"n": "Slot {n} water velocity is abnormal."}, # abnormal water velocity "n": "Slot {n} chip voltage changed.",
8: {0: "Chip temp calibration failed, please restore factory settings."}, },
9: {"n": "Slot {n} chip temp calibration check no balance."}, 3: {
"n": "Slot {n} chip temperature difference is too large.",
},
4: {
"n": "Slot {n} chip hottest temperature difference is too large.",
},
5: {"n": "Slot {n} stopped hashing, chips temperature protecting."},
7: {
"n": "Slot {n} water velocity is abnormal.",
}, # abnormal water velocity
8: {
0: "Chip temp calibration failed, please restore factory settings.",
},
9: {
"n": "Slot {n} chip temp calibration check no balance.",
},
}, },
51: { # frequency error 51: { # frequency error
1: {"n": "Slot {n} frequency up timeout."}, # frequency up timeout 1: {
7: {"n": "Slot {n} frequency up timeout."}, # frequency up timeout "n": "Slot {n} frequency up timeout.",
}, # frequency up timeout
2: {"n": "Slot {n} too many CRC errors."},
3: {"n": "Slot {n} unstable."},
7: {
"n": "Slot {n} frequency up timeout.",
}, # frequency up timeout
},
52: {
"n": {
"c": "Slot {n} chip {c} error nonce.",
},
},
53: {
"n": {
"c": "Slot {n} chip {c} too few nonce.",
},
},
54: {
"n": {
"c": "Slot {n} chip {c} temp protected.",
},
},
55: {
"n": {
"c": "Slot {n} chip {c} has been reset.",
},
},
56: {
"n": {
"c": "Slot {n} chip {c} zero nonce.",
},
}, },
52: {"n": {"c": "Slot {n} chip {c} error nonce."}},
53: {"n": {"c": "Slot {n} chip {c} too few nonce."}},
54: {"n": {"c": "Slot {n} chip {c} temp protected."}},
55: {"n": {"c": "Slot {n} chip {c} has been reset."}},
56: {"n": {"c": "Slot {n} chip {c} does not return to the nonce."}},
80: { 80: {
0: {0: "The tool version is too low, please update."}, 0: {
1: {0: "Low freq."}, 0: "The tool version is too low, please update.",
2: {0: "Low hashrate."}, },
3: {5: "High env temp."}, 1: {
0: "Low freq.",
},
2: {
0: "Low hashrate.",
},
3: {
5: "High env temp.",
},
}, },
81: { 81: {
0: {0: "Chip data error."}, 0: {
0: "Chip data error.",
},
}, },
82: { 82: {
0: {0: "Power version error."}, 0: {
1: {0: "Miner type error."}, 0: "Power version error.",
2: {0: "Version info error."}, },
1: {
0: "Miner type error.",
},
2: {
0: "Version info error.",
},
}, },
83: { 83: {
0: {0: "Empty level error."}, 0: {
0: "Empty level error.",
},
}, },
84: { 84: {
0: {0: "Old firmware."}, 0: {
1: {0: "Software version error."}, 0: "Old firmware.",
},
1: {
0: "Software version error.",
},
}, },
85: { 85: {
"n": { "n": {
@@ -296,8 +465,12 @@ ERROR_CODES = {
}, },
}, },
86: { 86: {
0: {0: "Missing product serial #."}, 0: {
1: {0: "Missing product type."}, 0: "Missing product serial #.",
},
1: {
0: "Missing product type.",
},
2: { 2: {
0: "Missing miner serial #.", 0: "Missing miner serial #.",
1: "Wrong miner serial # length.", 1: "Wrong miner serial # length.",
@@ -314,12 +487,34 @@ ERROR_CODES = {
3: "Wrong power model rate.", 3: "Wrong power model rate.",
4: "Wrong power model format.", 4: "Wrong power model format.",
}, },
5: {0: "Wrong hash board struct."}, 5: {
6: {0: "Wrong miner cooling type."}, 0: "Wrong hash board struct.",
7: {0: "Missing PCB serial #."}, },
6: {
0: "Wrong miner cooling type.",
},
7: {
0: "Missing PCB serial #.",
},
},
87: {
0: {
0: "Miner power mismatch.",
},
},
90: {
0: {
0: "Process error, exited with signal: 3.",
},
1: {
0: "Process error, exited with signal: 3.",
},
},
99: {
9: {
9: "Miner unknown error.",
},
}, },
87: {0: {0: "Miner power mismatch."}},
99: {9: {9: "Miner unknown error."}},
1000: { 1000: {
0: { 0: {
0: "Security library error, please upgrade firmware", 0: "Security library error, please upgrade firmware",
@@ -328,7 +523,11 @@ ERROR_CODES = {
3: "/antiv/dig/pf_partial.dig illegal.", 3: "/antiv/dig/pf_partial.dig illegal.",
}, },
}, },
1001: {0: {0: "Security BTMiner removed, please upgrade firmware."}}, 1001: {
0: {
0: "Security BTMiner removed, please upgrade firmware.",
},
},
1100: { 1100: {
0: { 0: {
0: "Security illegal file, please upgrade firmware.", 0: "Security illegal file, please upgrade firmware.",

View File

@@ -235,7 +235,20 @@ class BMMiner(BaseMiner):
if board_offset == -1: if board_offset == -1:
board_offset = 1 board_offset = 1
for i in range(board_offset, board_offset + self.ideal_hashboards): real_slots = []
for i in range(board_offset, board_offset + 4):
try:
key = f'chain_acs{i}'
if boards[1].get(key, '') != '':
real_slots.append(i)
except LookupError:
pass
if len(real_slots) < 3:
real_slots = list(range(board_offset, board_offset + self.ideal_hashboards))
for i in real_slots:
hashboard = HashBoard( hashboard = HashBoard(
slot=i - board_offset, expected_chips=self.nominal_chips slot=i - board_offset, expected_chips=self.nominal_chips
) )
@@ -259,7 +272,7 @@ class BMMiner(BaseMiner):
if (not chips) or (not chips > 0): if (not chips) or (not chips > 0):
hashboard.missing = True hashboard.missing = True
hashboards.append(hashboard) hashboards.append(hashboard)
except (IndexError, KeyError, ValueError, TypeError): except (LookupError, ValueError, TypeError):
pass pass
return hashboards return hashboards

View File

@@ -303,17 +303,12 @@ class BOSMiner(BaseMiner):
The config from `self.config`. The config from `self.config`.
""" """
logging.debug(f"{self}: Getting config.") logging.debug(f"{self}: Getting config.")
conn = None
try: try:
conn = await self._get_ssh_connection() conn = await self._get_ssh_connection()
except ConnectionError: except ConnectionError:
try: conn = None
pools = await self.api.pools()
except APIError:
return self.config
if pools:
self.config = MinerConfig().from_api(pools["POOLS"])
return self.config
if conn: if conn:
async with conn: async with conn:
# good ol' BBB compatibility :/ # good ol' BBB compatibility :/
@@ -365,6 +360,8 @@ class BOSMiner(BaseMiner):
async def set_power_limit(self, wattage: int) -> bool: async def set_power_limit(self, wattage: int) -> bool:
try: try:
cfg = await self.get_config() cfg = await self.get_config()
if cfg is None:
return False
cfg.autotuning_wattage = wattage cfg.autotuning_wattage = wattage
await self.send_config(cfg) await self.send_config(cfg)
except Exception as e: except Exception as e:

View File

@@ -179,11 +179,12 @@ class CGMinerAvalon(CGMiner):
pass pass
async def get_hostname(self, mac: str = None) -> Optional[str]: async def get_hostname(self, mac: str = None) -> Optional[str]:
if not mac: return None
mac = await self.get_mac() # if not mac:
# mac = await self.get_mac()
if mac: #
return f"Avalon{mac.replace(':', '')[-6:]}" # if mac:
# return f"Avalon{mac.replace(':', '')[-6:]}"
async def get_hashrate(self, api_devs: dict = None) -> Optional[float]: async def get_hashrate(self, api_devs: dict = None) -> Optional[float]:
if not api_devs: if not api_devs:

View File

@@ -413,21 +413,29 @@ class BaseMiner(ABC):
""" """
pass pass
async def _get_data(self, allow_warning: bool, data_to_get: list = None) -> dict: async def _get_data(
if not data_to_get: self, allow_warning: bool, include: list = None, exclude: list = None
) -> dict:
if include is None:
# everything # everything
data_to_get = list(self.data_locations.keys()) include = list(self.data_locations.keys())
if exclude is not None:
for item in exclude:
if item in include:
include.remove(item)
api_multicommand = set() api_multicommand = set()
web_multicommand = set() web_multicommand = []
for data_name in data_to_get: for data_name in include:
try: try:
fn_args = self.data_locations[data_name]["kwargs"] fn_args = self.data_locations[data_name]["kwargs"]
for arg_name in fn_args: for arg_name in fn_args:
if fn_args[arg_name].get("api"): if fn_args[arg_name].get("api"):
api_multicommand.add(fn_args[arg_name]["api"]) api_multicommand.add(fn_args[arg_name]["api"])
if fn_args[arg_name].get("web"): if fn_args[arg_name].get("web"):
web_multicommand.add(fn_args[arg_name]["web"]) if not fn_args[arg_name]["web"] in web_multicommand:
web_multicommand.append(fn_args[arg_name]["web"])
except KeyError as e: except KeyError as e:
logger.error(e, data_name) logger.error(e, data_name)
continue continue
@@ -445,8 +453,6 @@ class BaseMiner(ABC):
else: else:
web_command_task = asyncio.sleep(0) web_command_task = asyncio.sleep(0)
from datetime import datetime
web_command_data = await web_command_task web_command_data = await web_command_task
if web_command_data is None: if web_command_data is None:
web_command_data = {} web_command_data = {}
@@ -457,7 +463,7 @@ class BaseMiner(ABC):
miner_data = {} miner_data = {}
for data_name in data_to_get: for data_name in include:
try: try:
fn_args = self.data_locations[data_name]["kwargs"] fn_args = self.data_locations[data_name]["kwargs"]
args_to_send = {k: None for k in fn_args} args_to_send = {k: None for k in fn_args}
@@ -511,13 +517,14 @@ class BaseMiner(ABC):
return miner_data return miner_data
async def get_data( async def get_data(
self, allow_warning: bool = False, data_to_get: list = None self, allow_warning: bool = False, include: list = None, exclude: list = None
) -> MinerData: ) -> MinerData:
"""Get data from the miner in the form of [`MinerData`][pyasic.data.MinerData]. """Get data from the miner in the form of [`MinerData`][pyasic.data.MinerData].
Parameters: Parameters:
allow_warning: Allow warning when an API command fails. allow_warning: Allow warning when an API command fails.
data_to_get: Names of data items you want to gather. Defaults to all data. include: Names of data items you want to gather. Defaults to all data.
exclude: Names of data items to exclude. Exclusion happens after considering included items.
Returns: Returns:
A [`MinerData`][pyasic.data.MinerData] instance containing data from the miner. A [`MinerData`][pyasic.data.MinerData] instance containing data from the miner.
@@ -533,7 +540,9 @@ class BaseMiner(ABC):
], ],
) )
gathered_data = await self._get_data(allow_warning, data_to_get=data_to_get) gathered_data = await self._get_data(
allow_warning, include=include, exclude=exclude
)
for item in gathered_data: for item in gathered_data:
if gathered_data[item] is not None: if gathered_data[item] is not None:
setattr(data, item, gathered_data[item]) setattr(data, item, gathered_data[item])

View File

@@ -486,7 +486,7 @@ class MinerFactory:
"location", "" "location", ""
): ):
return MinerTypes.WHATSMINER return MinerTypes.WHATSMINER
if "Braiins OS" in web_text or 'href="/cgi-bin/luci"' in web_text: if "Braiins OS" in web_text:
return MinerTypes.BRAIINS_OS return MinerTypes.BRAIINS_OS
if "cloud-box" in web_text: if "cloud-box" in web_text:
return MinerTypes.GOLDSHELL return MinerTypes.GOLDSHELL
@@ -775,15 +775,13 @@ class MinerFactory:
f"http://{ip}/api/auth", f"http://{ip}/api/auth",
data={"username": "admin", "password": "admin"}, data={"username": "admin", "password": "admin"},
) )
auth = (await auth_req.json())["jwt"] auth = auth_req.json()["jwt"]
web_data = await ( web_data = (await session.post(
await session.post(
f"http://{ip}/api/type", f"http://{ip}/api/type",
headers={"Authorization": "Bearer " + auth}, headers={"Authorization": "Bearer " + auth},
data={}, data={},
) )).json()
).json()
return web_data["type"] return web_data["type"]
except (httpx.HTTPError, LookupError): except (httpx.HTTPError, LookupError):
pass pass
@@ -806,7 +804,7 @@ class MinerFactory:
json={"query": "{bosminer {info{modelName}}}"}, json={"query": "{bosminer {info{modelName}}}"},
) )
if d.status_code == 200: if d.status_code == 200:
json_data = await d.json() json_data = d.json()
miner_model = json_data["data"]["bosminer"]["info"]["modelName"] miner_model = json_data["data"]["bosminer"]["info"]["modelName"]
return miner_model return miner_model
except (httpx.HTTPError, LookupError): except (httpx.HTTPError, LookupError):

View File

@@ -24,8 +24,5 @@ class M29V10(WhatsMiner): # noqa - ignore ABC method implementation
super().__init__(ip, api_ver) super().__init__(ip, api_ver)
self.ip = ip self.ip = ip
self.model = "M29 V10" self.model = "M29 V10"
self.nominal_chips = 0 self.nominal_chips = 50
warnings.warn(
"Unknown chip count for miner type M29V10, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
)
self.fan_count = 2 self.fan_count = 2

View File

@@ -165,10 +165,7 @@ class M30SPlusVE50(WhatsMiner): # noqa - ignore ABC method implementation
super().__init__(ip, api_ver) super().__init__(ip, api_ver)
self.ip = ip self.ip = ip
self.model = "M30S+ VE50" self.model = "M30S+ VE50"
self.nominal_chips = 0 self.nominal_chips = 164
warnings.warn(
"Unknown chip count for miner type M30S+ VE50, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
)
self.fan_count = 2 self.fan_count = 2

View File

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