Update miner data and fix various bugs related to the fix. (#47)
* feature: fix influxdb data. * bug: fix an issue with some avalon stats parsing. * bug: add chip count for 1166 Pro. * bug: fix some issues with bosminer scanning and some data bugs. * bug: remove print statement. * bug: fix failed data gathering multicommand via graphql. * feature: add partial support for M50S+VK20 * version: bump version number. * bug: add chip count for M50S+VK20. * version: bump version number. * bug: attempt to fix offset check issue on BOS+. * bug: fix NoneType subscription on BOS+. * bug: add support for Vnish S17+. * bug: remove web references for Avalons. * bug: add support for VNish S17Pro. * bug: Try secondary identification method for antminers. * feature: fix a bunch of functionality for avalonminers. * bug: fix avalonminer fan speed being set as str. * bug: fix fans speeds being represented as strings. * bug: fix some get_fan formatting. * docs: update supported miners list, and fix A10X model name. * docs: update MinerData docstrings. * docs: update factory documentation.
This commit is contained in:
25
pyasic/miners/antminer/vnish/X17/S17.py
Normal file
25
pyasic/miners/antminer/vnish/X17/S17.py
Normal file
@@ -0,0 +1,25 @@
|
||||
# ------------------------------------------------------------------------------
|
||||
# Copyright 2022 Upstream Data Inc -
|
||||
# -
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); -
|
||||
# you may not use this file except in compliance with the License. -
|
||||
# You may obtain a copy of the License at -
|
||||
# -
|
||||
# http://www.apache.org/licenses/LICENSE-2.0 -
|
||||
# -
|
||||
# Unless required by applicable law or agreed to in writing, software -
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, -
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -
|
||||
# See the License for the specific language governing permissions and -
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
from pyasic.miners.backends import VNish
|
||||
from pyasic.miners.types import S17Plus, S17Pro
|
||||
|
||||
|
||||
class VNishS17Plus(VNish, S17Plus):
|
||||
pass
|
||||
|
||||
|
||||
class VNishS17Pro(VNish, S17Pro):
|
||||
pass
|
||||
16
pyasic/miners/antminer/vnish/X17/__init__.py
Normal file
16
pyasic/miners/antminer/vnish/X17/__init__.py
Normal file
@@ -0,0 +1,16 @@
|
||||
# ------------------------------------------------------------------------------
|
||||
# Copyright 2022 Upstream Data Inc -
|
||||
# -
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); -
|
||||
# you may not use this file except in compliance with the License. -
|
||||
# You may obtain a copy of the License at -
|
||||
# -
|
||||
# http://www.apache.org/licenses/LICENSE-2.0 -
|
||||
# -
|
||||
# Unless required by applicable law or agreed to in writing, software -
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, -
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -
|
||||
# See the License for the specific language governing permissions and -
|
||||
# limitations under the License. -
|
||||
# ------------------------------------------------------------------------------
|
||||
from .S17 import VNishS17Plus, VNishS17Pro
|
||||
@@ -15,4 +15,5 @@
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
from .X3 import *
|
||||
from .X17 import *
|
||||
from .X19 import *
|
||||
|
||||
@@ -353,7 +353,7 @@ class AntminerOld(CGMiner):
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
fans_data = [Fan(), Fan(), Fan(), Fan()]
|
||||
fans_data = [Fan() for _ in range(self.fan_count)]
|
||||
if api_stats:
|
||||
try:
|
||||
fan_offset = -1
|
||||
@@ -367,8 +367,8 @@ class AntminerOld(CGMiner):
|
||||
fan_offset = 3
|
||||
|
||||
for fan in range(self.fan_count):
|
||||
fans_data[fan] = Fan(
|
||||
api_stats["STATS"][1].get(f"fan{fan_offset+fan}")
|
||||
fans_data[fan].speed = api_stats["STATS"][1].get(
|
||||
f"fan{fan_offset+fan}", 0
|
||||
)
|
||||
except (KeyError, IndexError):
|
||||
pass
|
||||
|
||||
@@ -247,14 +247,16 @@ class BFGMiner(BaseMiner):
|
||||
|
||||
for fan_num in range(0, 8, 4):
|
||||
for _f_num in range(4):
|
||||
f = api_stats["STATS"][1].get(f"fan{fan_num + _f_num}")
|
||||
if f and not f == 0 and fan_offset == -1:
|
||||
f = api_stats["STATS"][1].get(f"fan{fan_num + _f_num}", 0)
|
||||
if not f == 0 and fan_offset == -1:
|
||||
fan_offset = fan_num
|
||||
if fan_offset == -1:
|
||||
fan_offset = 1
|
||||
|
||||
for fan in range(self.fan_count):
|
||||
fans_data[fan] = api_stats["STATS"][1].get(f"fan{fan_offset+fan}")
|
||||
fans_data[fan] = api_stats["STATS"][1].get(
|
||||
f"fan{fan_offset+fan}", 0
|
||||
)
|
||||
except (KeyError, IndexError):
|
||||
pass
|
||||
fans = [Fan(speed=d) if d else Fan() for d in fans_data]
|
||||
|
||||
@@ -275,24 +275,25 @@ class BMMiner(BaseMiner):
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
fans_data = [None, None, None, None]
|
||||
fans = [Fan() for _ in range(self.fan_count)]
|
||||
if api_stats:
|
||||
try:
|
||||
fan_offset = -1
|
||||
|
||||
for fan_num in range(1, 8, 4):
|
||||
for _f_num in range(4):
|
||||
f = api_stats["STATS"][1].get(f"fan{fan_num + _f_num}")
|
||||
f = api_stats["STATS"][1].get(f"fan{fan_num + _f_num}", 0)
|
||||
if f and not f == 0 and fan_offset == -1:
|
||||
fan_offset = fan_num
|
||||
if fan_offset == -1:
|
||||
fan_offset = 1
|
||||
|
||||
for fan in range(self.fan_count):
|
||||
fans_data[fan] = api_stats["STATS"][1].get(f"fan{fan_offset+fan}")
|
||||
fans[fan].speed = api_stats["STATS"][1].get(
|
||||
f"fan{fan_offset+fan}", 0
|
||||
)
|
||||
except (KeyError, IndexError):
|
||||
pass
|
||||
fans = [Fan(speed=d) if d else Fan() for d in fans_data]
|
||||
|
||||
return fans
|
||||
|
||||
|
||||
@@ -155,7 +155,7 @@ BOSMINER_DATA_LOC = {
|
||||
"config": {
|
||||
"... on BosminerConfig": {
|
||||
"groups": {
|
||||
"pools": {"urluser": None},
|
||||
"pools": {"url": None, "user": None},
|
||||
"strategy": {
|
||||
"... on QuotaStrategy": {"quota": None}
|
||||
},
|
||||
@@ -414,7 +414,7 @@ class BOSMiner(BaseMiner):
|
||||
|
||||
if graphql_version:
|
||||
try:
|
||||
fw_ver = graphql_version["bos"]["info"]["version"]["full"]
|
||||
fw_ver = graphql_version["data"]["bos"]["info"]["version"]["full"]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
@@ -442,7 +442,7 @@ class BOSMiner(BaseMiner):
|
||||
|
||||
if graphql_hostname:
|
||||
try:
|
||||
hostname = graphql_hostname["bos"]["hostname"]
|
||||
hostname = graphql_hostname["data"]["bos"]["hostname"]
|
||||
return hostname
|
||||
except KeyError:
|
||||
pass
|
||||
@@ -477,7 +477,7 @@ class BOSMiner(BaseMiner):
|
||||
try:
|
||||
return round(
|
||||
float(
|
||||
graphql_hashrate["bosminer"]["info"]["workSolver"][
|
||||
graphql_hashrate["data"]["bosminer"]["info"]["workSolver"][
|
||||
"realHashrate"
|
||||
]["mhs1M"]
|
||||
/ 1000000
|
||||
@@ -535,14 +535,19 @@ class BOSMiner(BaseMiner):
|
||||
|
||||
if graphql_boards:
|
||||
try:
|
||||
boards = graphql_boards["bosminer"]["info"]["workSolver"][
|
||||
boards = graphql_boards["data"]["bosminer"]["info"]["workSolver"][
|
||||
"childSolvers"
|
||||
]
|
||||
except (KeyError, IndexError):
|
||||
boards = None
|
||||
|
||||
if boards:
|
||||
offset = 6 if int(boards[0]["name"]) in [6, 7, 8] else 0
|
||||
b_names = [int(b["name"]) for b in boards]
|
||||
offset = 0
|
||||
if 3 in b_names:
|
||||
offset = 1
|
||||
elif 6 in b_names:
|
||||
offset = 6
|
||||
for hb in boards:
|
||||
_id = int(hb["name"]) - offset
|
||||
board = hashboards[_id]
|
||||
@@ -643,13 +648,12 @@ class BOSMiner(BaseMiner):
|
||||
)
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
if graphql_wattage:
|
||||
if graphql_wattage is not None:
|
||||
try:
|
||||
return graphql_wattage["bosminer"]["info"]["workSolver"]["power"][
|
||||
"approxConsumptionW"
|
||||
]
|
||||
except KeyError:
|
||||
return graphql_wattage["data"]["bosminer"]["info"]["workSolver"][
|
||||
"power"
|
||||
]["approxConsumptionW"]
|
||||
except (KeyError, TypeError):
|
||||
pass
|
||||
|
||||
if not api_tunerstatus:
|
||||
@@ -679,10 +683,10 @@ class BOSMiner(BaseMiner):
|
||||
|
||||
if graphql_wattage_limit:
|
||||
try:
|
||||
return graphql_wattage_limit["bosminer"]["info"]["workSolver"]["power"][
|
||||
"limitW"
|
||||
]
|
||||
except KeyError:
|
||||
return graphql_wattage_limit["data"]["bosminer"]["info"]["workSolver"][
|
||||
"power"
|
||||
]["limitW"]
|
||||
except (KeyError, TypeError):
|
||||
pass
|
||||
|
||||
if not api_tunerstatus:
|
||||
@@ -707,17 +711,20 @@ class BOSMiner(BaseMiner):
|
||||
)
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
if graphql_fans:
|
||||
fans = {"fan_1": Fan(), "fan_2": Fan(), "fan_3": Fan(), "fan_4": Fan()}
|
||||
fans = []
|
||||
for n in range(self.fan_count):
|
||||
try:
|
||||
fans[f"fan_{n + 1}"].speed = graphql_fans["bosminer"]["info"][
|
||||
"fans"
|
||||
][n]["rpm"]
|
||||
fans.append(
|
||||
Fan(
|
||||
speed=graphql_fans["data"]["bosminer"]["info"]["fans"][n][
|
||||
"rpm"
|
||||
]
|
||||
)
|
||||
)
|
||||
except KeyError:
|
||||
pass
|
||||
return [fans["fan_1"], fans["fan_2"], fans["fan_3"], fans["fan_4"]]
|
||||
return fans
|
||||
|
||||
if not api_fans:
|
||||
try:
|
||||
@@ -726,14 +733,14 @@ class BOSMiner(BaseMiner):
|
||||
pass
|
||||
|
||||
if api_fans:
|
||||
fans = {"fan_1": Fan(), "fan_2": Fan(), "fan_3": Fan(), "fan_4": Fan()}
|
||||
fans = []
|
||||
for n in range(self.fan_count):
|
||||
try:
|
||||
fans[f"fan_{n + 1}"].speed = api_fans["FANS"][n]["RPM"]
|
||||
fans.append(Fan(api_fans["FANS"][n]["RPM"]))
|
||||
except (IndexError, KeyError):
|
||||
pass
|
||||
return [fans["fan_1"], fans["fan_2"], fans["fan_3"], fans["fan_4"]]
|
||||
return [Fan(), Fan(), Fan(), Fan()]
|
||||
return fans
|
||||
return [Fan() for _ in range(self.fan_count)]
|
||||
|
||||
async def get_fan_psu(self) -> Optional[int]:
|
||||
return None
|
||||
@@ -763,7 +770,7 @@ class BOSMiner(BaseMiner):
|
||||
if graphql_pools:
|
||||
groups = []
|
||||
try:
|
||||
g = graphql_pools["bosminer"]["config"]["groups"]
|
||||
g = graphql_pools["data"]["bosminer"]["config"]["groups"]
|
||||
for group in g:
|
||||
pools = {"quota": group["strategy"]["quota"]}
|
||||
for i, pool in enumerate(group["pools"]):
|
||||
@@ -775,7 +782,7 @@ class BOSMiner(BaseMiner):
|
||||
pools[f"pool_{i + 1}_user"] = pool["user"]
|
||||
groups.append(pools)
|
||||
return groups
|
||||
except KeyError:
|
||||
except (KeyError, TypeError):
|
||||
pass
|
||||
|
||||
if not api_pools:
|
||||
@@ -852,7 +859,7 @@ class BOSMiner(BaseMiner):
|
||||
if graphql_errors:
|
||||
errors = []
|
||||
try:
|
||||
boards = graphql_errors["bosminer"]["info"]["workSolver"][
|
||||
boards = graphql_errors["data"]["bosminer"]["info"]["workSolver"][
|
||||
"childSolvers"
|
||||
]
|
||||
except (KeyError, IndexError):
|
||||
@@ -946,7 +953,7 @@ class BOSMiner(BaseMiner):
|
||||
# get light through GraphQL
|
||||
if graphql_fault_light:
|
||||
try:
|
||||
self.light = graphql_fault_light["bos"]["faultLight"]
|
||||
self.light = graphql_fault_light["data"]["bos"]["faultLight"]
|
||||
return self.light
|
||||
except (TypeError, KeyError, ValueError, IndexError):
|
||||
pass
|
||||
|
||||
@@ -463,15 +463,13 @@ class BTMiner(BaseMiner):
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
fans = [Fan(), Fan(), Fan(), Fan()]
|
||||
fans = [Fan() for _ in range(self.fan_count)]
|
||||
if api_summary:
|
||||
try:
|
||||
if self.fan_count > 0:
|
||||
fans = [
|
||||
Fan(api_summary["SUMMARY"][0]["Fan Speed In"]),
|
||||
Fan(api_summary["SUMMARY"][0]["Fan Speed Out"]),
|
||||
Fan(),
|
||||
Fan(),
|
||||
Fan(api_summary["SUMMARY"][0].get("Fan Speed In", 0)),
|
||||
Fan(api_summary["SUMMARY"][0].get("Fan Speed Out", 0)),
|
||||
]
|
||||
except (KeyError, IndexError):
|
||||
pass
|
||||
|
||||
@@ -296,7 +296,7 @@ class CGMiner(BaseMiner):
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
fans_data = [Fan(), Fan(), Fan(), Fan()]
|
||||
fans = [Fan() for _ in range(self.fan_count)]
|
||||
if api_stats:
|
||||
try:
|
||||
fan_offset = -1
|
||||
@@ -310,12 +310,12 @@ class CGMiner(BaseMiner):
|
||||
fan_offset = 1
|
||||
|
||||
for fan in range(self.fan_count):
|
||||
fans_data[fan] = Fan(
|
||||
api_stats["STATS"][1].get(f"fan{fan_offset+fan}")
|
||||
fans[fan].speed = api_stats["STATS"][1].get(
|
||||
f"fan{fan_offset+fan}", 0
|
||||
)
|
||||
except (KeyError, IndexError):
|
||||
pass
|
||||
return fans_data
|
||||
return fans
|
||||
|
||||
async def get_fan_psu(self) -> Optional[int]:
|
||||
return None
|
||||
|
||||
@@ -29,20 +29,26 @@ AVALON_DATA_LOC = {
|
||||
"model": {"cmd": "get_model", "kwargs": {}},
|
||||
"api_ver": {"cmd": "get_api_ver", "kwargs": {"api_version": {"api": "version"}}},
|
||||
"fw_ver": {"cmd": "get_fw_ver", "kwargs": {"api_version": {"api": "version"}}},
|
||||
"hostname": {"cmd": "get_hostname", "kwargs": {"mac": {"web": "mac"}}},
|
||||
"hashrate": {"cmd": "get_hashrate", "kwargs": {"api_summary": {"api": "summary"}}},
|
||||
"hostname": {"cmd": "get_hostname", "kwargs": {"mac": {"api": "version"}}},
|
||||
"hashrate": {"cmd": "get_hashrate", "kwargs": {"api_devs": {"api": "devs"}}},
|
||||
"nominal_hashrate": {
|
||||
"cmd": "get_nominal_hashrate",
|
||||
"kwargs": {"api_stats": {"api": "stats"}},
|
||||
},
|
||||
"hashboards": {"cmd": "get_hashboards", "kwargs": {"api_stats": {"api": "stats"}}},
|
||||
"env_temp": {"cmd": "get_env_temp", "kwargs": {}},
|
||||
"env_temp": {"cmd": "get_env_temp", "kwargs": {"api_stats": {"api": "stats"}}},
|
||||
"wattage": {"cmd": "get_wattage", "kwargs": {}},
|
||||
"wattage_limit": {"cmd": "get_wattage_limit", "kwargs": {}},
|
||||
"wattage_limit": {
|
||||
"cmd": "get_wattage_limit",
|
||||
"kwargs": {"api_stats": {"api": "stats"}},
|
||||
},
|
||||
"fans": {"cmd": "get_fans", "kwargs": {"api_stats": {"api": "stats"}}},
|
||||
"fan_psu": {"cmd": "get_fan_psu", "kwargs": {}},
|
||||
"errors": {"cmd": "get_errors", "kwargs": {}},
|
||||
"fault_light": {"cmd": "get_fault_light", "kwargs": {}},
|
||||
"fault_light": {
|
||||
"cmd": "get_fault_light",
|
||||
"kwargs": {"api_stats": {"api": "stats"}},
|
||||
},
|
||||
"pools": {"cmd": "get_pools", "kwargs": {"api_pools": {"api": "pools"}}},
|
||||
}
|
||||
|
||||
@@ -115,8 +121,17 @@ class CGMinerAvalon(CGMiner):
|
||||
data = item.replace("]", "").split("[")
|
||||
data_list = [i.split(": ") for i in data[1].strip().split(", ")]
|
||||
data_dict = {}
|
||||
for key, val in [tuple(item) for item in data_list]:
|
||||
data_dict[key] = val
|
||||
try:
|
||||
for key, val in [tuple(item) for item in data_list]:
|
||||
data_dict[key] = val
|
||||
except ValueError:
|
||||
# --avalon args
|
||||
for arg_item in data_list:
|
||||
item_data = arg_item[0].split(" ")
|
||||
for idx in range(len(item_data)):
|
||||
if idx % 2 == 0 or idx == 0:
|
||||
data_dict[item_data[idx]] = item_data[idx + 1]
|
||||
|
||||
raw_data = [data[0].strip(), data_dict]
|
||||
else:
|
||||
raw_data = [
|
||||
@@ -168,16 +183,16 @@ class CGMinerAvalon(CGMiner):
|
||||
if mac:
|
||||
return f"Avalon{mac.replace(':', '')[-6:]}"
|
||||
|
||||
async def get_hashrate(self, api_summary: dict = None) -> Optional[float]:
|
||||
if not api_summary:
|
||||
async def get_hashrate(self, api_devs: dict = None) -> Optional[float]:
|
||||
if not api_devs:
|
||||
try:
|
||||
api_summary = await self.api.summary()
|
||||
api_devs = await self.api.devs()
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
if api_summary:
|
||||
if api_devs:
|
||||
try:
|
||||
return round(float(api_summary["SUMMARY"][0]["MHS 1m"] / 1000000), 2)
|
||||
return round(float(api_devs["DEVS"][0]["MHS 1m"] / 1000000), 2)
|
||||
except (KeyError, IndexError, ValueError, TypeError):
|
||||
pass
|
||||
|
||||
@@ -195,38 +210,87 @@ class CGMinerAvalon(CGMiner):
|
||||
|
||||
if api_stats:
|
||||
try:
|
||||
stats_data = api_stats[0].get("STATS")
|
||||
if stats_data:
|
||||
for key in stats_data[0].keys():
|
||||
if key.startswith("MM ID"):
|
||||
raw_data = self.parse_stats(stats_data[0][key])
|
||||
for board in range(self.ideal_hashboards):
|
||||
chip_temp = raw_data.get("MTmax")
|
||||
if chip_temp:
|
||||
hashboards[board].chip_temp = chip_temp[board]
|
||||
|
||||
temp = raw_data.get("MTavg")
|
||||
if temp:
|
||||
hashboards[board].temp = temp[board]
|
||||
|
||||
chips = raw_data.get(f"PVT_T{board}")
|
||||
if chips:
|
||||
hashboards[board].chips = len(
|
||||
[item for item in chips if not item == "0"]
|
||||
)
|
||||
unparsed_stats = api_stats["STATS"][0]["MM ID0"]
|
||||
parsed_stats = self.parse_stats(unparsed_stats)
|
||||
except (IndexError, KeyError, ValueError, TypeError):
|
||||
pass
|
||||
return hashboards
|
||||
|
||||
for board in range(self.ideal_hashboards):
|
||||
try:
|
||||
hashboards[board].chip_temp = int(parsed_stats["MTmax"][board])
|
||||
except LookupError:
|
||||
pass
|
||||
|
||||
try:
|
||||
board_hr = parsed_stats["MGHS"][board]
|
||||
hashboards[board].hashrate = round(float(board_hr) / 1000, 2)
|
||||
except LookupError:
|
||||
pass
|
||||
|
||||
try:
|
||||
hashboards[board].temp = int(parsed_stats["MTavg"][board])
|
||||
except LookupError:
|
||||
pass
|
||||
|
||||
try:
|
||||
chip_data = parsed_stats[f"PVT_T{board}"]
|
||||
hashboards[board].missing = False
|
||||
if chip_data:
|
||||
hashboards[board].chips = len(
|
||||
[item for item in chip_data if not item == "0"]
|
||||
)
|
||||
except LookupError:
|
||||
pass
|
||||
|
||||
return hashboards
|
||||
|
||||
async def get_env_temp(self) -> Optional[float]:
|
||||
return None
|
||||
async def get_nominal_hashrate(self, api_stats: dict = None) -> Optional[float]:
|
||||
if not api_stats:
|
||||
try:
|
||||
api_stats = await self.api.stats()
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
if api_stats:
|
||||
try:
|
||||
unparsed_stats = api_stats["STATS"][0]["MM ID0"]
|
||||
parsed_stats = self.parse_stats(unparsed_stats)
|
||||
return round(float(parsed_stats["GHSmm"]) / 1000, 2)
|
||||
except (IndexError, KeyError, ValueError, TypeError):
|
||||
pass
|
||||
|
||||
async def get_env_temp(self, api_stats: dict = None) -> Optional[float]:
|
||||
if not api_stats:
|
||||
try:
|
||||
api_stats = await self.api.stats()
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
if api_stats:
|
||||
try:
|
||||
unparsed_stats = api_stats["STATS"][0]["MM ID0"]
|
||||
parsed_stats = self.parse_stats(unparsed_stats)
|
||||
return float(parsed_stats["Temp"])
|
||||
except (IndexError, KeyError, ValueError, TypeError):
|
||||
pass
|
||||
|
||||
async def get_wattage(self) -> Optional[int]:
|
||||
return None
|
||||
|
||||
async def get_wattage_limit(self) -> Optional[int]:
|
||||
return None
|
||||
async def get_wattage_limit(self, api_stats: dict = None) -> Optional[int]:
|
||||
if not api_stats:
|
||||
try:
|
||||
api_stats = await self.api.stats()
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
if api_stats:
|
||||
try:
|
||||
unparsed_stats = api_stats["STATS"][0]["MM ID0"]
|
||||
parsed_stats = self.parse_stats(unparsed_stats)
|
||||
return int(parsed_stats["MPO"])
|
||||
except (IndexError, KeyError, ValueError, TypeError):
|
||||
pass
|
||||
|
||||
async def get_fans(self, api_stats: dict = None) -> List[Fan]:
|
||||
if not api_stats:
|
||||
@@ -235,19 +299,19 @@ class CGMinerAvalon(CGMiner):
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
fans_data = [Fan(), Fan(), Fan(), Fan()]
|
||||
fans_data = [Fan() for _ in range(self.fan_count)]
|
||||
if api_stats:
|
||||
try:
|
||||
stats_data = api_stats[0].get("STATS")
|
||||
if stats_data:
|
||||
for key in stats_data[0].keys():
|
||||
if key.startswith("MM ID"):
|
||||
raw_data = self.parse_stats(stats_data[0][key])
|
||||
for fan in range(self.fan_count):
|
||||
fans_data[fan] = Fan(int(raw_data[f"Fan{fan + 1}"]))
|
||||
except (KeyError, IndexError, ValueError, TypeError):
|
||||
pass
|
||||
unparsed_stats = api_stats["STATS"][0]["MM ID0"]
|
||||
parsed_stats = self.parse_stats(unparsed_stats)
|
||||
except LookupError:
|
||||
return fans_data
|
||||
|
||||
for fan in range(self.fan_count):
|
||||
try:
|
||||
fans_data[fan].speed = int(parsed_stats[f"Fan{fan + 1}"])
|
||||
except (IndexError, KeyError, ValueError, TypeError):
|
||||
pass
|
||||
return fans_data
|
||||
|
||||
async def get_pools(self, api_pools: dict = None) -> List[dict]:
|
||||
@@ -279,13 +343,31 @@ class CGMinerAvalon(CGMiner):
|
||||
async def get_errors(self) -> List[MinerErrorData]:
|
||||
return []
|
||||
|
||||
async def get_fault_light(self) -> bool:
|
||||
async def get_fault_light(self, api_stats: dict = None) -> bool: # noqa
|
||||
if self.light:
|
||||
return self.light
|
||||
if not api_stats:
|
||||
try:
|
||||
api_stats = await self.api.stats()
|
||||
except APIError:
|
||||
pass
|
||||
|
||||
if api_stats:
|
||||
try:
|
||||
unparsed_stats = api_stats["STATS"][0]["MM ID0"]
|
||||
parsed_stats = self.parse_stats(unparsed_stats)
|
||||
led = int(parsed_stats["Led"])
|
||||
return True if led == 1 else False
|
||||
except (IndexError, KeyError, ValueError, TypeError):
|
||||
pass
|
||||
|
||||
try:
|
||||
data = await self.api.ascset(0, "led", "1-255")
|
||||
except APIError:
|
||||
return False
|
||||
if data["STATUS"][0]["Msg"] == "ASC 0 set info: LED[1]":
|
||||
return True
|
||||
try:
|
||||
if data["STATUS"][0]["Msg"] == "ASC 0 set info: LED[1]":
|
||||
return True
|
||||
except LookupError:
|
||||
pass
|
||||
return False
|
||||
|
||||
@@ -254,7 +254,7 @@ class CGMinerA10X(CGMiner, A10X):
|
||||
else:
|
||||
web_get_all = web_get_all["all"]
|
||||
|
||||
fan_data = [Fan(), Fan(), Fan(), Fan()]
|
||||
fans = [Fan() for _ in range(self.fan_count)]
|
||||
if web_get_all:
|
||||
try:
|
||||
spd = web_get_all["fansSpeed"]
|
||||
@@ -263,9 +263,9 @@ class CGMinerA10X(CGMiner, A10X):
|
||||
else:
|
||||
round((int(spd) * 6000) / 100)
|
||||
for i in range(self.fan_count):
|
||||
fan_data[i] = Fan(spd)
|
||||
fans[i].speed = spd
|
||||
|
||||
return fan_data
|
||||
return fans
|
||||
|
||||
async def get_pools(self, api_pools: dict = None) -> List[dict]:
|
||||
groups = []
|
||||
|
||||
@@ -236,7 +236,7 @@ class CGMinerT3HPlus(CGMiner, T3HPlus):
|
||||
else:
|
||||
web_get_all = web_get_all["all"]
|
||||
|
||||
fan_data = [Fan(), Fan(), Fan(), Fan()]
|
||||
fans = [Fan() for _ in range(self.fan_count)]
|
||||
if web_get_all:
|
||||
try:
|
||||
spd = web_get_all["fansSpeed"]
|
||||
@@ -245,9 +245,9 @@ class CGMinerT3HPlus(CGMiner, T3HPlus):
|
||||
else:
|
||||
round((int(spd) * 6000) / 100)
|
||||
for i in range(self.fan_count):
|
||||
fan_data[i] = Fan(spd)
|
||||
fans[i].speed = spd
|
||||
|
||||
return fan_data
|
||||
return fans
|
||||
|
||||
async def get_pools(self, api_pools: dict = None) -> List[dict]:
|
||||
groups = []
|
||||
|
||||
@@ -61,10 +61,10 @@ class MinerTypes(enum.Enum):
|
||||
MINER_CLASSES = {
|
||||
MinerTypes.ANTMINER: {
|
||||
None: BMMiner,
|
||||
"ANTMINER DR5": CGMinerDR5,
|
||||
"ANTMINER D3": CGMinerD3,
|
||||
"ANTMINER HS3": BMMinerHS3,
|
||||
"ANTMINER L3+": BMMinerL3Plus,
|
||||
"ANTMINER DR5": CGMinerDR5,
|
||||
"ANTMINER L7": BMMinerL7,
|
||||
"ANTMINER E9 PRO": BMMinerE9Pro,
|
||||
"ANTMINER S9": BMMinerS9,
|
||||
@@ -322,6 +322,8 @@ MINER_CLASSES = {
|
||||
MinerTypes.VNISH: {
|
||||
None: VNish,
|
||||
"ANTMINER L3+": VnishL3Plus,
|
||||
"ANTMINER S17+": VNishS17Plus,
|
||||
"ANTMINER S17 PRO": VNishS17Pro,
|
||||
"ANTMINER S19": VNishS19,
|
||||
"ANTMINER S19 PRO": VNishS19Pro,
|
||||
"ANTMINER S19J": VNishS19j,
|
||||
@@ -393,7 +395,9 @@ class MinerFactory:
|
||||
ip = str(ip)
|
||||
if ip in self.cache:
|
||||
return self.cache[ip]
|
||||
|
||||
miner_type = None
|
||||
|
||||
for _ in range(RETRIES):
|
||||
task = asyncio.create_task(self._get_miner_type(ip))
|
||||
try:
|
||||
@@ -406,23 +410,18 @@ class MinerFactory:
|
||||
|
||||
if miner_type is not None:
|
||||
miner_model = None
|
||||
fn = None
|
||||
if miner_type == MinerTypes.ANTMINER:
|
||||
fn = self.get_miner_model_antminer
|
||||
if miner_type == MinerTypes.WHATSMINER:
|
||||
fn = self.get_miner_model_whatsminer
|
||||
if miner_type == MinerTypes.AVALONMINER:
|
||||
fn = self.get_miner_model_avalonminer
|
||||
if miner_type == MinerTypes.INNOSILICON:
|
||||
fn = self.get_miner_model_innosilicon
|
||||
if miner_type == MinerTypes.GOLDSHELL:
|
||||
fn = self.get_miner_model_goldshell
|
||||
if miner_type == MinerTypes.BRAIINS_OS:
|
||||
fn = self.get_miner_model_braiins_os
|
||||
if miner_type == MinerTypes.VNISH:
|
||||
fn = self.get_miner_model_vnish
|
||||
if miner_type == MinerTypes.HIVEON:
|
||||
fn = self.get_miner_model_hiveon
|
||||
miner_model_fns = {
|
||||
MinerTypes.ANTMINER: self.get_miner_model_antminer,
|
||||
MinerTypes.WHATSMINER: self.get_miner_model_whatsminer,
|
||||
MinerTypes.AVALONMINER: self.get_miner_model_avalonminer,
|
||||
MinerTypes.INNOSILICON: self.get_miner_model_innosilicon,
|
||||
MinerTypes.GOLDSHELL: self.get_miner_model_goldshell,
|
||||
MinerTypes.BRAIINS_OS: self.get_miner_model_braiins_os,
|
||||
MinerTypes.VNISH: self.get_miner_model_vnish,
|
||||
MinerTypes.HIVEON: self.get_miner_model_hiveon,
|
||||
}
|
||||
fn = miner_model_fns.get(miner_type)
|
||||
|
||||
if fn is not None:
|
||||
task = asyncio.create_task(fn(ip))
|
||||
try:
|
||||
@@ -433,6 +432,7 @@ class MinerFactory:
|
||||
miner = self._select_miner_from_classes(
|
||||
ip, miner_type=miner_type, miner_model=miner_model
|
||||
)
|
||||
|
||||
if miner is not None and not isinstance(miner, UnknownMiner):
|
||||
self.cache[ip] = miner
|
||||
return miner
|
||||
@@ -464,7 +464,7 @@ class MinerFactory:
|
||||
try:
|
||||
resp = await session.get(url)
|
||||
return await resp.text(), resp
|
||||
except aiohttp.ClientError:
|
||||
except (aiohttp.ClientError, asyncio.TimeoutError):
|
||||
pass
|
||||
return None, None
|
||||
|
||||
@@ -680,6 +680,22 @@ class MinerFactory:
|
||||
try:
|
||||
miner_model = sock_json_data["VERSION"][0]["Type"]
|
||||
|
||||
if " (" in miner_model:
|
||||
split_miner_model = miner_model.split(" (")
|
||||
miner_model = split_miner_model[0]
|
||||
|
||||
return miner_model
|
||||
except (TypeError, LookupError):
|
||||
pass
|
||||
|
||||
sock_json_data = await self.send_api_command(ip, "stats")
|
||||
try:
|
||||
miner_model = sock_json_data["STATS"][0]["Type"]
|
||||
|
||||
if " (" in miner_model:
|
||||
split_miner_model = miner_model.split(" (")
|
||||
miner_model = split_miner_model[0]
|
||||
|
||||
return miner_model
|
||||
except (TypeError, LookupError):
|
||||
pass
|
||||
@@ -761,7 +777,8 @@ class MinerFactory:
|
||||
try:
|
||||
async with aiohttp.ClientSession() as session:
|
||||
d = await session.post(
|
||||
url, json={"query": "{bosminer {info{modelName}}}"}
|
||||
f"http://{ip}/graphql",
|
||||
json={"query": "{bosminer {info{modelName}}}"},
|
||||
)
|
||||
if d.status == 200:
|
||||
json_data = await d.json()
|
||||
@@ -773,9 +790,9 @@ class MinerFactory:
|
||||
async def get_miner_model_vnish(self, ip: str) -> Optional[str]:
|
||||
sock_json_data = await self.send_api_command(ip, "stats")
|
||||
try:
|
||||
miner_model = sock_json_data["STATS"][0]["Type"].upper()
|
||||
if " (VNISH" in miner_model:
|
||||
split_miner_model = miner_model.split(" (VNISH ")
|
||||
miner_model = sock_json_data["STATS"][0]["Type"]
|
||||
if " (" in miner_model:
|
||||
split_miner_model = miner_model.split(" (")
|
||||
miner_model = split_miner_model[0]
|
||||
|
||||
return miner_model
|
||||
|
||||
@@ -22,8 +22,6 @@ class Avalon1166Pro(AvalonMiner): # 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 = "Avalon 1166"
|
||||
warnings.warn(
|
||||
f"Unknown chip count for miner type {self.model}, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
|
||||
)
|
||||
self.model = "Avalon 1166 Pro"
|
||||
self.nominal_chips = 120
|
||||
self.fan_count = 4
|
||||
|
||||
@@ -20,3 +20,4 @@ class A10X(InnosiliconMiner): # noqa - ignore ABC method implementation
|
||||
def __init__(self, ip: str, api_ver: str = "0.0.0") -> None:
|
||||
super().__init__(ip, api_ver)
|
||||
self.ip = ip
|
||||
self.model = "A10X"
|
||||
|
||||
Reference in New Issue
Block a user