Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
895f17aaf9 | ||
|
|
8a64ff3559 | ||
|
|
4c45d356c4 | ||
|
|
4dec329f11 | ||
|
|
b563ed118e | ||
|
|
75b2ec40b1 | ||
|
|
d9adaf6667 | ||
|
|
9343308f41 | ||
|
|
88769e40ae | ||
|
|
be45eb7400 | ||
|
|
2f719a03a4 | ||
|
|
64196f9754 |
@@ -108,31 +108,31 @@ class MiningModeHPM(MinerConfigValue):
|
|||||||
return {"mode": {"mode": "turbo"}}
|
return {"mode": {"mode": "turbo"}}
|
||||||
|
|
||||||
|
|
||||||
class StandardPowerTuneAlgo(MinerConfigValue):
|
class StandardTuneAlgo(MinerConfigValue):
|
||||||
mode: str = field(init=False, default="standard")
|
mode: str = field(init=False, default="standard")
|
||||||
|
|
||||||
def as_epic(self) -> str:
|
def as_epic(self) -> str:
|
||||||
return VOptPowerTuneAlgo().as_epic()
|
return VOptAlgo().as_epic()
|
||||||
|
|
||||||
|
|
||||||
class VOptPowerTuneAlgo(MinerConfigValue):
|
class VOptAlgo(MinerConfigValue):
|
||||||
mode: str = field(init=False, default="standard")
|
mode: str = field(init=False, default="standard")
|
||||||
|
|
||||||
def as_epic(self) -> str:
|
def as_epic(self) -> str:
|
||||||
return "VoltageOptimizer"
|
return "VoltageOptimizer"
|
||||||
|
|
||||||
|
|
||||||
class ChipTunePowerTuneAlgo(MinerConfigValue):
|
class ChipTuneAlgo(MinerConfigValue):
|
||||||
mode: str = field(init=False, default="standard")
|
mode: str = field(init=False, default="standard")
|
||||||
|
|
||||||
def as_epic(self) -> str:
|
def as_epic(self) -> str:
|
||||||
return "ChipTune"
|
return "ChipTune"
|
||||||
|
|
||||||
|
|
||||||
class PowerTunerAlgo(MinerConfigOption):
|
class TunerAlgo(MinerConfigOption):
|
||||||
standard = StandardPowerTuneAlgo
|
standard = StandardTuneAlgo
|
||||||
voltage_optimizer = VOptPowerTuneAlgo
|
voltage_optimizer = VOptAlgo
|
||||||
chip_tune = ChipTunePowerTuneAlgo
|
chip_tune = ChipTuneAlgo
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def default(cls):
|
def default(cls):
|
||||||
@@ -143,7 +143,7 @@ class PowerTunerAlgo(MinerConfigOption):
|
|||||||
class MiningModePowerTune(MinerConfigValue):
|
class MiningModePowerTune(MinerConfigValue):
|
||||||
mode: str = field(init=False, default="power_tuning")
|
mode: str = field(init=False, default="power_tuning")
|
||||||
power: int = None
|
power: int = None
|
||||||
algo: PowerTunerAlgo = field(default_factory=PowerTunerAlgo.default)
|
algo: TunerAlgo = field(default_factory=TunerAlgo.default)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_dict(cls, dict_conf: dict | None) -> "MiningModePowerTune":
|
def from_dict(cls, dict_conf: dict | None) -> "MiningModePowerTune":
|
||||||
@@ -183,14 +183,12 @@ class MiningModePowerTune(MinerConfigValue):
|
|||||||
def as_auradine(self) -> dict:
|
def as_auradine(self) -> dict:
|
||||||
return {"mode": {"mode": "custom", "tune": "power", "power": self.power}}
|
return {"mode": {"mode": "custom", "tune": "power", "power": self.power}}
|
||||||
|
|
||||||
def as_epic(self) -> dict:
|
|
||||||
return {"ptune": {"algo": self.algo.as_epic(), "target": self.power}}
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class MiningModeHashrateTune(MinerConfigValue):
|
class MiningModeHashrateTune(MinerConfigValue):
|
||||||
mode: str = field(init=False, default="hashrate_tuning")
|
mode: str = field(init=False, default="hashrate_tuning")
|
||||||
hashrate: int = None
|
hashrate: int = None
|
||||||
|
algo: TunerAlgo = field(default_factory=TunerAlgo.default)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_dict(cls, dict_conf: dict | None) -> "MiningModeHashrateTune":
|
def from_dict(cls, dict_conf: dict | None) -> "MiningModeHashrateTune":
|
||||||
@@ -218,6 +216,9 @@ class MiningModeHashrateTune(MinerConfigValue):
|
|||||||
def as_auradine(self) -> dict:
|
def as_auradine(self) -> dict:
|
||||||
return {"mode": {"mode": "custom", "tune": "ths", "ths": self.hashrate}}
|
return {"mode": {"mode": "custom", "tune": "ths", "ths": self.hashrate}}
|
||||||
|
|
||||||
|
def as_epic(self) -> dict:
|
||||||
|
return {"ptune": {"algo": self.algo.as_epic(), "target": self.hashrate}}
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class ManualBoardSettings(MinerConfigValue):
|
class ManualBoardSettings(MinerConfigValue):
|
||||||
@@ -313,14 +314,14 @@ class MiningModeConfig(MinerConfigOption):
|
|||||||
if tuner_running:
|
if tuner_running:
|
||||||
algo_info = web_conf["PerpetualTune"]["Algorithm"]
|
algo_info = web_conf["PerpetualTune"]["Algorithm"]
|
||||||
if algo_info.get("VoltageOptimizer") is not None:
|
if algo_info.get("VoltageOptimizer") is not None:
|
||||||
return cls.power_tuning(
|
return cls.hashrate_tuning(
|
||||||
power=algo_info["VoltageOptimizer"]["Target"],
|
hashrate=algo_info["VoltageOptimizer"]["Target"],
|
||||||
algo=PowerTunerAlgo.voltage_optimizer,
|
algo=TunerAlgo.voltage_optimizer,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
return cls.power_tuning(
|
return cls.hashrate_tuning(
|
||||||
power=algo_info["ChipTune"]["Target"],
|
hashrate=algo_info["ChipTune"]["Target"],
|
||||||
algo=PowerTunerAlgo.chip_tune,
|
algo=TunerAlgo.chip_tune,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
return cls.normal()
|
return cls.normal()
|
||||||
|
|||||||
@@ -14,21 +14,21 @@
|
|||||||
# limitations under the License. -
|
# limitations under the License. -
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import BOSer
|
from pyasic.miners.backends import BOSMiner
|
||||||
from pyasic.miners.models import S17, S17e, S17Plus, S17Pro
|
from pyasic.miners.models import S17, S17e, S17Plus, S17Pro
|
||||||
|
|
||||||
|
|
||||||
class BOSMinerS17(BOSer, S17):
|
class BOSMinerS17(BOSMiner, S17):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class BOSMinerS17Plus(BOSer, S17Plus):
|
class BOSMinerS17Plus(BOSMiner, S17Plus):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class BOSMinerS17Pro(BOSer, S17Pro):
|
class BOSMinerS17Pro(BOSMiner, S17Pro):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class BOSMinerS17e(BOSer, S17e):
|
class BOSMinerS17e(BOSMiner, S17e):
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -14,17 +14,17 @@
|
|||||||
# limitations under the License. -
|
# limitations under the License. -
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import BOSer
|
from pyasic.miners.backends import BOSMiner
|
||||||
from pyasic.miners.models import T17, T17e, T17Plus
|
from pyasic.miners.models import T17, T17e, T17Plus
|
||||||
|
|
||||||
|
|
||||||
class BOSMinerT17(BOSer, T17):
|
class BOSMinerT17(BOSMiner, T17):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class BOSMinerT17Plus(BOSer, T17Plus):
|
class BOSMinerT17Plus(BOSMiner, T17Plus):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class BOSMinerT17e(BOSer, T17e):
|
class BOSMinerT17e(BOSMiner, T17e):
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -205,13 +205,14 @@ class VNish(BMMiner):
|
|||||||
if web_summary is None:
|
if web_summary is None:
|
||||||
web_summary = await self.web.summary()
|
web_summary = await self.web.summary()
|
||||||
|
|
||||||
|
fw_ver = None
|
||||||
if web_summary is not None:
|
if web_summary is not None:
|
||||||
try:
|
try:
|
||||||
fw_ver = web_summary["miner"]["miner_type"]
|
fw_ver = web_summary["miner"]["miner_type"]
|
||||||
fw_ver = fw_ver.split("(Vnish ")[1].replace(")", "")
|
fw_ver = fw_ver.split("(Vnish ")[1].replace(")", "")
|
||||||
return fw_ver
|
return fw_ver
|
||||||
except KeyError:
|
except LookupError:
|
||||||
pass
|
return fw_ver
|
||||||
|
|
||||||
async def get_config(self) -> MinerConfig:
|
async def get_config(self) -> MinerConfig:
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -289,7 +289,9 @@ MINER_CLASSES = {
|
|||||||
"M50S++VK30": BTMinerM50SPlusPlusVK30,
|
"M50S++VK30": BTMinerM50SPlusPlusVK30,
|
||||||
"M53VH30": BTMinerM53VH30,
|
"M53VH30": BTMinerM53VH30,
|
||||||
"M53SVH30": BTMinerM53SVH30,
|
"M53SVH30": BTMinerM53SVH30,
|
||||||
|
"M53SVJ40": BTMinerM53SVJ40,
|
||||||
"M53S+VJ30": BTMinerM53SPlusVJ30,
|
"M53S+VJ30": BTMinerM53SPlusVJ30,
|
||||||
|
"M53S++VK10": BTMinerM53SPlusPlusVK10,
|
||||||
"M56VH30": BTMinerM56VH30,
|
"M56VH30": BTMinerM56VH30,
|
||||||
"M56SVH30": BTMinerM56SVH30,
|
"M56SVH30": BTMinerM56SVH30,
|
||||||
"M56S+VJ30": BTMinerM56SPlusVJ30,
|
"M56S+VJ30": BTMinerM56SPlusVJ30,
|
||||||
@@ -968,6 +970,7 @@ class MinerFactory:
|
|||||||
|
|
||||||
miner_factory = MinerFactory()
|
miner_factory = MinerFactory()
|
||||||
|
|
||||||
|
|
||||||
# abstracted version of get miner that is easier to access
|
# abstracted version of get miner that is easier to access
|
||||||
async def get_miner(ip: ipaddress.ip_address | str) -> AnyMiner:
|
async def get_miner(ip: ipaddress.ip_address | str) -> AnyMiner:
|
||||||
return await miner_factory.get_miner(ip)
|
return await miner_factory.get_miner(ip)
|
||||||
|
|||||||
@@ -20,3 +20,8 @@ from pyasic.miners.makes import WhatsMinerMake
|
|||||||
class M53SVH30(WhatsMinerMake):
|
class M53SVH30(WhatsMinerMake):
|
||||||
raw_model = "M53S VH30"
|
raw_model = "M53S VH30"
|
||||||
expected_fans = 0
|
expected_fans = 0
|
||||||
|
|
||||||
|
|
||||||
|
class M53SVJ40(WhatsMinerMake):
|
||||||
|
raw_model = "M53S VJ40"
|
||||||
|
expected_fans = 0
|
||||||
|
|||||||
22
pyasic/miners/models/whatsminer/M5X/M53S_Plus_Plus.py
Normal file
22
pyasic/miners/models/whatsminer/M5X/M53S_Plus_Plus.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# 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.makes import WhatsMinerMake
|
||||||
|
|
||||||
|
|
||||||
|
class M53SPlusPlusVK10(WhatsMinerMake):
|
||||||
|
raw_model = "M53S++ VK10"
|
||||||
|
expected_fans = 0
|
||||||
@@ -42,8 +42,9 @@ from .M50S import (
|
|||||||
from .M50S_Plus import M50SPlusVH30, M50SPlusVH40, M50SPlusVJ30, M50SPlusVK20
|
from .M50S_Plus import M50SPlusVH30, M50SPlusVH40, M50SPlusVJ30, M50SPlusVK20
|
||||||
from .M50S_Plus_Plus import M50SPlusPlusVK10, M50SPlusPlusVK20, M50SPlusPlusVK30
|
from .M50S_Plus_Plus import M50SPlusPlusVK10, M50SPlusPlusVK20, M50SPlusPlusVK30
|
||||||
from .M53 import M53VH30
|
from .M53 import M53VH30
|
||||||
from .M53S import M53SVH30
|
from .M53S import M53SVH30, M53SVJ40
|
||||||
from .M53S_Plus import M53SPlusVJ30
|
from .M53S_Plus import M53SPlusVJ30
|
||||||
|
from .M53S_Plus_Plus import M53SPlusPlusVK10
|
||||||
from .M56 import M56VH30
|
from .M56 import M56VH30
|
||||||
from .M56S import M56SVH30
|
from .M56S import M56SVH30
|
||||||
from .M56S_Plus import M56SPlusVJ30
|
from .M56S_Plus import M56SPlusVJ30
|
||||||
|
|||||||
@@ -15,8 +15,12 @@
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
from pyasic.miners.backends import M5X
|
from pyasic.miners.backends import M5X
|
||||||
from pyasic.miners.models import M53SVH30
|
from pyasic.miners.models import M53SVH30, M53SVJ40
|
||||||
|
|
||||||
|
|
||||||
class BTMinerM53SVH30(M5X, M53SVH30):
|
class BTMinerM53SVH30(M5X, M53SVH30):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class BTMinerM53SVJ40(M5X, M53SVJ40):
|
||||||
|
pass
|
||||||
|
|||||||
22
pyasic/miners/whatsminer/btminer/M5X/M53S_Plus_Plus.py
Normal file
22
pyasic/miners/whatsminer/btminer/M5X/M53S_Plus_Plus.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# 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 M5X
|
||||||
|
from pyasic.miners.models import M53SPlusPlusVK10
|
||||||
|
|
||||||
|
|
||||||
|
class BTMinerM53SPlusPlusVK10(M5X, M53SPlusPlusVK10):
|
||||||
|
pass
|
||||||
@@ -51,8 +51,9 @@ from .M50S_Plus_Plus import (
|
|||||||
BTMinerM50SPlusPlusVK30,
|
BTMinerM50SPlusPlusVK30,
|
||||||
)
|
)
|
||||||
from .M53 import BTMinerM53VH30
|
from .M53 import BTMinerM53VH30
|
||||||
from .M53S import BTMinerM53SVH30
|
from .M53S import BTMinerM53SVH30, BTMinerM53SVJ40
|
||||||
from .M53S_Plus import BTMinerM53SPlusVJ30
|
from .M53S_Plus import BTMinerM53SPlusVJ30
|
||||||
|
from .M53S_Plus_Plus import BTMinerM53SPlusPlusVK10
|
||||||
from .M56 import BTMinerM56VH30
|
from .M56 import BTMinerM56VH30
|
||||||
from .M56S import BTMinerM56SVH30
|
from .M56S import BTMinerM56SVH30
|
||||||
from .M56S_Plus import BTMinerM56SPlusVJ30
|
from .M56S_Plus import BTMinerM56SPlusVJ30
|
||||||
|
|||||||
@@ -78,6 +78,9 @@ class BaseMinerRPCAPI:
|
|||||||
# send the command
|
# send the command
|
||||||
data = await self._send_bytes(json.dumps(cmd).encode("utf-8"))
|
data = await self._send_bytes(json.dumps(cmd).encode("utf-8"))
|
||||||
|
|
||||||
|
if data is None:
|
||||||
|
raise APIError("No data returned from the API.")
|
||||||
|
|
||||||
if data == b"Socket connect failed: Connection refused\n":
|
if data == b"Socket connect failed: Connection refused\n":
|
||||||
if not ignore_errors:
|
if not ignore_errors:
|
||||||
raise APIError(data.decode("utf-8"))
|
raise APIError(data.decode("utf-8"))
|
||||||
@@ -208,39 +211,14 @@ If you are sure you want to use this command please use API.send_command("{comma
|
|||||||
return b"{}"
|
return b"{}"
|
||||||
|
|
||||||
# send the command
|
# send the command
|
||||||
|
data_task = asyncio.create_task(self._read_bytes(reader, timeout=timeout))
|
||||||
logging.debug(f"{self} - ([Hidden] Send Bytes) - Writing")
|
logging.debug(f"{self} - ([Hidden] Send Bytes) - Writing")
|
||||||
writer.write(data)
|
writer.write(data)
|
||||||
logging.debug(f"{self} - ([Hidden] Send Bytes) - Draining")
|
logging.debug(f"{self} - ([Hidden] Send Bytes) - Draining")
|
||||||
await writer.drain()
|
await writer.drain()
|
||||||
try:
|
|
||||||
# TO address a situation where a whatsminer has an unknown PW -AND-
|
|
||||||
# Fix for stupid whatsminer bug, reboot/restart seem to not load properly in the loop
|
|
||||||
# have to receive, save the data, check if there is more data by reading with a short timeout
|
|
||||||
# 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:
|
|
||||||
return b"{}"
|
|
||||||
try:
|
|
||||||
ret_data += await asyncio.wait_for(reader.read(4096), timeout=timeout)
|
|
||||||
except ConnectionAbortedError:
|
|
||||||
return b"{}"
|
|
||||||
|
|
||||||
# loop to receive all the data
|
await data_task
|
||||||
logging.debug(f"{self} - ([Hidden] Send Bytes) - Receiving")
|
ret_data = data_task.result()
|
||||||
try:
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
d = await asyncio.wait_for(reader.read(4096), timeout=timeout)
|
|
||||||
if not d:
|
|
||||||
break
|
|
||||||
ret_data += d
|
|
||||||
except (asyncio.CancelledError, asyncio.TimeoutError) as e:
|
|
||||||
raise e
|
|
||||||
except (asyncio.CancelledError, asyncio.TimeoutError) as e:
|
|
||||||
raise e
|
|
||||||
except Exception as e:
|
|
||||||
logging.warning(f"{self} - ([Hidden] Send Bytes) - API Command Error {e}")
|
|
||||||
|
|
||||||
# close the connection
|
# close the connection
|
||||||
logging.debug(f"{self} - ([Hidden] Send Bytes) - Closing")
|
logging.debug(f"{self} - ([Hidden] Send Bytes) - Closing")
|
||||||
@@ -249,6 +227,19 @@ If you are sure you want to use this command please use API.send_command("{comma
|
|||||||
|
|
||||||
return ret_data
|
return ret_data
|
||||||
|
|
||||||
|
async def _read_bytes(self, reader: asyncio.StreamReader, timeout: int) -> bytes:
|
||||||
|
ret_data = b""
|
||||||
|
|
||||||
|
# loop to receive all the data
|
||||||
|
logging.debug(f"{self} - ([Hidden] Send Bytes) - Receiving")
|
||||||
|
try:
|
||||||
|
ret_data = await asyncio.wait_for(reader.read(), timeout=timeout)
|
||||||
|
except (asyncio.CancelledError, asyncio.TimeoutError) as e:
|
||||||
|
raise e
|
||||||
|
except Exception as e:
|
||||||
|
logging.warning(f"{self} - ([Hidden] Send Bytes) - API Command Error {e}")
|
||||||
|
return ret_data
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _load_api_data(data: bytes) -> dict:
|
def _load_api_data(data: bytes) -> dict:
|
||||||
# some json from the API returns with a null byte (\x00) on the end
|
# some json from the API returns with a null byte (\x00) on the end
|
||||||
|
|||||||
@@ -607,10 +607,10 @@ class BTMinerRPCAPI(BaseMinerRPCAPI):
|
|||||||
A reply informing of the status of setting the frequency.
|
A reply informing of the status of setting the frequency.
|
||||||
</details>
|
</details>
|
||||||
"""
|
"""
|
||||||
if not -10 < percent < 100:
|
if not -100 < percent < 100:
|
||||||
raise APIError(
|
raise APIError(
|
||||||
f"Frequency % is outside of the allowed "
|
f"Frequency % is outside of the allowed "
|
||||||
f"range. Please set a % between -10 and "
|
f"range. Please set a % between -100 and "
|
||||||
f"100"
|
f"100"
|
||||||
)
|
)
|
||||||
return await self.send_privileged_command(
|
return await self.send_privileged_command(
|
||||||
|
|||||||
@@ -70,13 +70,15 @@ class BOSerWebAPI(BaseWebAPI):
|
|||||||
not func.startswith("__") and not func.startswith("_")
|
not func.startswith("__") and not func.startswith("_")
|
||||||
]
|
]
|
||||||
|
|
||||||
async def multicommand(self, *commands: str) -> dict:
|
async def multicommand(
|
||||||
|
self, *commands: str, ignore_errors: bool = False, allow_warning: bool = True
|
||||||
|
) -> dict:
|
||||||
result = {"multicommand": True}
|
result = {"multicommand": True}
|
||||||
tasks = {}
|
tasks = {}
|
||||||
for command in commands:
|
for command in commands:
|
||||||
try:
|
try:
|
||||||
tasks[command] = asyncio.create_task(getattr(self, command)())
|
tasks[command] = asyncio.create_task(getattr(self, command)())
|
||||||
except AttributeError:
|
except (APIError, AttributeError):
|
||||||
result["command"] = {}
|
result["command"] = {}
|
||||||
|
|
||||||
await asyncio.gather(*list(tasks.values()))
|
await asyncio.gather(*list(tasks.values()))
|
||||||
|
|||||||
@@ -59,10 +59,14 @@ class BOSMinerWebAPI(BaseWebAPI):
|
|||||||
return {}
|
return {}
|
||||||
raise APIError(f"LUCI web command failed: command={command}")
|
raise APIError(f"LUCI web command failed: command={command}")
|
||||||
|
|
||||||
async def multicommand(self, *commands: str) -> dict:
|
async def multicommand(
|
||||||
|
self, *commands: str, ignore_errors: bool = False, allow_warning: bool = True
|
||||||
|
) -> dict:
|
||||||
data = {}
|
data = {}
|
||||||
for command in commands:
|
for command in commands:
|
||||||
data[command] = await self.send_command(command, ignore_errors=True)
|
data[command] = await self.send_command(
|
||||||
|
command, ignore_errors=ignore_errors
|
||||||
|
)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
async def auth(self, session: httpx.AsyncClient) -> None:
|
async def auth(self, session: httpx.AsyncClient) -> None:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "pyasic"
|
name = "pyasic"
|
||||||
version = "0.50.4"
|
version = "0.50.9"
|
||||||
description = "A simplified and standardized interface for Bitcoin ASICs."
|
description = "A simplified and standardized interface for Bitcoin ASICs."
|
||||||
authors = ["UpstreamData <brett@upstreamdata.ca>"]
|
authors = ["UpstreamData <brett@upstreamdata.ca>"]
|
||||||
repository = "https://github.com/UpstreamData/pyasic"
|
repository = "https://github.com/UpstreamData/pyasic"
|
||||||
|
|||||||
Reference in New Issue
Block a user