refactor: make web handlers much more consistent across types, remove graphql, and make luci and grpc the dedicated web apis for BOSer and BOSMiner respectively.
This commit is contained in:
@@ -29,7 +29,6 @@ from pyasic.miners.base import (
|
|||||||
DataFunction,
|
DataFunction,
|
||||||
DataLocations,
|
DataLocations,
|
||||||
DataOptions,
|
DataOptions,
|
||||||
GRPCCommand,
|
|
||||||
RPCAPICommand,
|
RPCAPICommand,
|
||||||
WebAPICommand,
|
WebAPICommand,
|
||||||
)
|
)
|
||||||
@@ -275,7 +274,7 @@ class BOSMiner(BaseMiner):
|
|||||||
async def _get_mac(self, web_net_conf: Union[dict, list] = None) -> Optional[str]:
|
async def _get_mac(self, web_net_conf: Union[dict, list] = None) -> Optional[str]:
|
||||||
if web_net_conf is None:
|
if web_net_conf is None:
|
||||||
try:
|
try:
|
||||||
web_net_conf = await self.web.luci.get_net_conf()
|
web_net_conf = await self.web.get_net_conf()
|
||||||
except APIError:
|
except APIError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -314,7 +313,7 @@ class BOSMiner(BaseMiner):
|
|||||||
async def _get_fw_ver(self, web_bos_info: dict = None) -> Optional[str]:
|
async def _get_fw_ver(self, web_bos_info: dict = None) -> Optional[str]:
|
||||||
if web_bos_info is None:
|
if web_bos_info is None:
|
||||||
try:
|
try:
|
||||||
web_bos_info = await self.web.luci.get_bos_info()
|
web_bos_info = await self.web.get_bos_info()
|
||||||
except APIError:
|
except APIError:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -571,19 +570,19 @@ BOSER_DATA_LOC = DataLocations(
|
|||||||
**{
|
**{
|
||||||
str(DataOptions.MAC): DataFunction(
|
str(DataOptions.MAC): DataFunction(
|
||||||
"_get_mac",
|
"_get_mac",
|
||||||
[GRPCCommand("grpc_miner_details", "get_miner_details")],
|
[WebAPICommand("grpc_miner_details", "get_miner_details")],
|
||||||
),
|
),
|
||||||
str(DataOptions.API_VERSION): DataFunction(
|
str(DataOptions.API_VERSION): DataFunction(
|
||||||
"_get_api_ver",
|
"_get_api_ver",
|
||||||
[GRPCCommand("api_version", "get_api_version")],
|
[RPCAPICommand("api_version", "version")],
|
||||||
),
|
),
|
||||||
str(DataOptions.FW_VERSION): DataFunction(
|
str(DataOptions.FW_VERSION): DataFunction(
|
||||||
"_get_fw_ver",
|
"_get_fw_ver",
|
||||||
[GRPCCommand("grpc_miner_details", "get_miner_details")],
|
[WebAPICommand("grpc_miner_details", "get_miner_details")],
|
||||||
),
|
),
|
||||||
str(DataOptions.HOSTNAME): DataFunction(
|
str(DataOptions.HOSTNAME): DataFunction(
|
||||||
"_get_hostname",
|
"_get_hostname",
|
||||||
[GRPCCommand("grpc_miner_details", "get_miner_details")],
|
[WebAPICommand("grpc_miner_details", "get_miner_details")],
|
||||||
),
|
),
|
||||||
str(DataOptions.HASHRATE): DataFunction(
|
str(DataOptions.HASHRATE): DataFunction(
|
||||||
"_get_hashrate",
|
"_get_hashrate",
|
||||||
@@ -591,27 +590,27 @@ BOSER_DATA_LOC = DataLocations(
|
|||||||
),
|
),
|
||||||
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
|
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
|
||||||
"_get_expected_hashrate",
|
"_get_expected_hashrate",
|
||||||
[GRPCCommand("grpc_miner_details", "get_miner_details")],
|
[WebAPICommand("grpc_miner_details", "get_miner_details")],
|
||||||
),
|
),
|
||||||
str(DataOptions.HASHBOARDS): DataFunction(
|
str(DataOptions.HASHBOARDS): DataFunction(
|
||||||
"_get_hashboards",
|
"_get_hashboards",
|
||||||
[GRPCCommand("grpc_hashboards", "get_hashboards")],
|
[WebAPICommand("grpc_hashboards", "get_hashboards")],
|
||||||
),
|
),
|
||||||
str(DataOptions.WATTAGE): DataFunction(
|
str(DataOptions.WATTAGE): DataFunction(
|
||||||
"_get_wattage",
|
"_get_wattage",
|
||||||
[GRPCCommand("grpc_miner_stats", "get_miner_stats")],
|
[WebAPICommand("grpc_miner_stats", "get_miner_stats")],
|
||||||
),
|
),
|
||||||
str(DataOptions.WATTAGE_LIMIT): DataFunction(
|
str(DataOptions.WATTAGE_LIMIT): DataFunction(
|
||||||
"_get_wattage_limit",
|
"_get_wattage_limit",
|
||||||
[
|
[
|
||||||
GRPCCommand(
|
WebAPICommand(
|
||||||
"grpc_active_performance_mode", "get_active_performance_mode"
|
"grpc_active_performance_mode", "get_active_performance_mode"
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
str(DataOptions.FANS): DataFunction(
|
str(DataOptions.FANS): DataFunction(
|
||||||
"_get_fans",
|
"_get_fans",
|
||||||
[GRPCCommand("grpc_cooling_state", "get_cooling_state")],
|
[WebAPICommand("grpc_cooling_state", "get_cooling_state")],
|
||||||
),
|
),
|
||||||
str(DataOptions.ERRORS): DataFunction(
|
str(DataOptions.ERRORS): DataFunction(
|
||||||
"_get_errors",
|
"_get_errors",
|
||||||
@@ -619,7 +618,7 @@ BOSER_DATA_LOC = DataLocations(
|
|||||||
),
|
),
|
||||||
str(DataOptions.FAULT_LIGHT): DataFunction(
|
str(DataOptions.FAULT_LIGHT): DataFunction(
|
||||||
"_get_fault_light",
|
"_get_fault_light",
|
||||||
[GRPCCommand("grpc_locate_device_status", "get_locate_device_status")],
|
[WebAPICommand("grpc_locate_device_status", "get_locate_device_status")],
|
||||||
),
|
),
|
||||||
str(DataOptions.IS_MINING): DataFunction(
|
str(DataOptions.IS_MINING): DataFunction(
|
||||||
"_is_mining",
|
"_is_mining",
|
||||||
@@ -647,13 +646,13 @@ class BOSer(BaseMiner):
|
|||||||
supports_shutdown = True
|
supports_shutdown = True
|
||||||
|
|
||||||
async def fault_light_on(self) -> bool:
|
async def fault_light_on(self) -> bool:
|
||||||
resp = await self.web.grpc.set_locate_device_status(True)
|
resp = await self.web.set_locate_device_status(True)
|
||||||
if resp.get("enabled", False):
|
if resp.get("enabled", False):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
async def fault_light_off(self) -> bool:
|
async def fault_light_off(self) -> bool:
|
||||||
resp = await self.web.grpc.set_locate_device_status(False)
|
resp = await self.web.set_locate_device_status(False)
|
||||||
if resp == {}:
|
if resp == {}:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
@@ -662,37 +661,37 @@ class BOSer(BaseMiner):
|
|||||||
return await self.restart_boser()
|
return await self.restart_boser()
|
||||||
|
|
||||||
async def restart_boser(self) -> bool:
|
async def restart_boser(self) -> bool:
|
||||||
await self.web.grpc.restart()
|
await self.web.restart()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
async def stop_mining(self) -> bool:
|
async def stop_mining(self) -> bool:
|
||||||
try:
|
try:
|
||||||
await self.web.grpc.pause_mining()
|
await self.web.pause_mining()
|
||||||
except APIError:
|
except APIError:
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
async def resume_mining(self) -> bool:
|
async def resume_mining(self) -> bool:
|
||||||
try:
|
try:
|
||||||
await self.web.grpc.resume_mining()
|
await self.web.resume_mining()
|
||||||
except APIError:
|
except APIError:
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
async def reboot(self) -> bool:
|
async def reboot(self) -> bool:
|
||||||
ret = await self.web.grpc.reboot()
|
ret = await self.web.reboot()
|
||||||
if ret == {}:
|
if ret == {}:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
async def get_config(self) -> MinerConfig:
|
async def get_config(self) -> MinerConfig:
|
||||||
grpc_conf = await self.web.grpc.get_miner_configuration()
|
grpc_conf = await self.web.get_miner_configuration()
|
||||||
|
|
||||||
return MinerConfig.from_boser(grpc_conf)
|
return MinerConfig.from_boser(grpc_conf)
|
||||||
|
|
||||||
async def set_power_limit(self, wattage: int) -> bool:
|
async def set_power_limit(self, wattage: int) -> bool:
|
||||||
try:
|
try:
|
||||||
result = await self.web.grpc.set_power_target(wattage)
|
result = await self.web.set_power_target(wattage)
|
||||||
except APIError:
|
except APIError:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -710,7 +709,7 @@ class BOSer(BaseMiner):
|
|||||||
async def _get_mac(self, grpc_miner_details: dict = None) -> Optional[str]:
|
async def _get_mac(self, grpc_miner_details: dict = None) -> Optional[str]:
|
||||||
if grpc_miner_details is None:
|
if grpc_miner_details is None:
|
||||||
try:
|
try:
|
||||||
grpc_miner_details = await self.web.grpc.get_miner_details()
|
grpc_miner_details = await self.web.get_miner_details()
|
||||||
except APIError:
|
except APIError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -740,7 +739,7 @@ class BOSer(BaseMiner):
|
|||||||
async def _get_fw_ver(self, grpc_miner_details: dict = None) -> Optional[str]:
|
async def _get_fw_ver(self, grpc_miner_details: dict = None) -> Optional[str]:
|
||||||
if grpc_miner_details is None:
|
if grpc_miner_details is None:
|
||||||
try:
|
try:
|
||||||
grpc_miner_details = await self.web.grpc.get_miner_details()
|
grpc_miner_details = await self.web.get_miner_details()
|
||||||
except APIError:
|
except APIError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -763,7 +762,7 @@ class BOSer(BaseMiner):
|
|||||||
async def _get_hostname(self, grpc_miner_details: dict = None) -> Optional[str]:
|
async def _get_hostname(self, grpc_miner_details: dict = None) -> Optional[str]:
|
||||||
if grpc_miner_details is None:
|
if grpc_miner_details is None:
|
||||||
try:
|
try:
|
||||||
grpc_miner_details = await self.web.grpc.get_miner_details()
|
grpc_miner_details = await self.web.get_miner_details()
|
||||||
except APIError:
|
except APIError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -791,7 +790,7 @@ class BOSer(BaseMiner):
|
|||||||
) -> Optional[float]:
|
) -> Optional[float]:
|
||||||
if grpc_miner_details is None:
|
if grpc_miner_details is None:
|
||||||
try:
|
try:
|
||||||
grpc_miner_details = await self.web.grpc.get_miner_details()
|
grpc_miner_details = await self.web.get_miner_details()
|
||||||
except APIError:
|
except APIError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -809,7 +808,7 @@ class BOSer(BaseMiner):
|
|||||||
|
|
||||||
if grpc_hashboards is None:
|
if grpc_hashboards is None:
|
||||||
try:
|
try:
|
||||||
grpc_hashboards = await self.web.grpc.get_hashboards()
|
grpc_hashboards = await self.web.get_hashboards()
|
||||||
except APIError:
|
except APIError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -840,7 +839,7 @@ class BOSer(BaseMiner):
|
|||||||
async def _get_wattage(self, grpc_miner_stats: dict = None) -> Optional[int]:
|
async def _get_wattage(self, grpc_miner_stats: dict = None) -> Optional[int]:
|
||||||
if grpc_miner_stats is None:
|
if grpc_miner_stats is None:
|
||||||
try:
|
try:
|
||||||
grpc_miner_stats = self.web.grpc.get_miner_stats()
|
grpc_miner_stats = self.web.get_miner_stats()
|
||||||
except APIError:
|
except APIError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -855,9 +854,7 @@ class BOSer(BaseMiner):
|
|||||||
) -> Optional[int]:
|
) -> Optional[int]:
|
||||||
if grpc_active_performance_mode is None:
|
if grpc_active_performance_mode is None:
|
||||||
try:
|
try:
|
||||||
grpc_active_performance_mode = (
|
grpc_active_performance_mode = self.web.get_active_performance_mode()
|
||||||
self.web.grpc.get_active_performance_mode()
|
|
||||||
)
|
|
||||||
except APIError:
|
except APIError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -872,7 +869,7 @@ class BOSer(BaseMiner):
|
|||||||
async def _get_fans(self, grpc_cooling_state: dict = None) -> List[Fan]:
|
async def _get_fans(self, grpc_cooling_state: dict = None) -> List[Fan]:
|
||||||
if grpc_cooling_state is None:
|
if grpc_cooling_state is None:
|
||||||
try:
|
try:
|
||||||
grpc_cooling_state = self.web.grpc.get_cooling_state()
|
grpc_cooling_state = self.web.get_cooling_state()
|
||||||
except APIError:
|
except APIError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -922,9 +919,7 @@ class BOSer(BaseMiner):
|
|||||||
|
|
||||||
if grpc_locate_device_status is None:
|
if grpc_locate_device_status is None:
|
||||||
try:
|
try:
|
||||||
grpc_locate_device_status = (
|
grpc_locate_device_status = await self.web.get_locate_device_status()
|
||||||
await self.web.grpc.get_locate_device_status()
|
|
||||||
)
|
|
||||||
except APIError:
|
except APIError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -76,18 +76,12 @@ class GRPCCommand(WebAPICommand):
|
|||||||
cmd: str
|
cmd: str
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class GraphQLCommand(WebAPICommand):
|
|
||||||
name: str
|
|
||||||
cmd: dict
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class DataFunction:
|
class DataFunction:
|
||||||
cmd: str
|
cmd: str
|
||||||
kwargs: List[
|
kwargs: List[Union[RPCAPICommand, WebAPICommand, GRPCCommand]] = field(
|
||||||
Union[RPCAPICommand, WebAPICommand, GRPCCommand, GraphQLCommand]
|
default_factory=list
|
||||||
] = field(default_factory=list)
|
)
|
||||||
|
|
||||||
def __call__(self, *args, **kwargs):
|
def __call__(self, *args, **kwargs):
|
||||||
return self
|
return self
|
||||||
|
|||||||
@@ -13,9 +13,11 @@
|
|||||||
# See the License for the specific language governing permissions and -
|
# See the License for the specific language governing permissions and -
|
||||||
# limitations under the License. -
|
# limitations under the License. -
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import warnings
|
import warnings
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
from typing import Union
|
from typing import Any
|
||||||
|
|
||||||
from pyasic.errors import APIWarning
|
from pyasic.errors import APIWarning
|
||||||
|
|
||||||
@@ -23,11 +25,13 @@ from pyasic.errors import APIWarning
|
|||||||
class BaseWebAPI(ABC):
|
class BaseWebAPI(ABC):
|
||||||
def __init__(self, ip: str) -> None:
|
def __init__(self, ip: str) -> None:
|
||||||
# ip address of the miner
|
# ip address of the miner
|
||||||
self.ip = ip # ipaddress.ip_address(ip)
|
self.ip = ip
|
||||||
self.username = "root"
|
self.username = None
|
||||||
self.pwd = None
|
self.pwd = None
|
||||||
self.port = 80
|
self.port = 80
|
||||||
|
|
||||||
|
self.token = None
|
||||||
|
|
||||||
def __new__(cls, *args, **kwargs):
|
def __new__(cls, *args, **kwargs):
|
||||||
if cls is BaseWebAPI:
|
if cls is BaseWebAPI:
|
||||||
raise TypeError(f"Only children of '{cls.__name__}' may be instantiated")
|
raise TypeError(f"Only children of '{cls.__name__}' may be instantiated")
|
||||||
@@ -39,10 +43,11 @@ class BaseWebAPI(ABC):
|
|||||||
@abstractmethod
|
@abstractmethod
|
||||||
async def send_command(
|
async def send_command(
|
||||||
self,
|
self,
|
||||||
command: Union[str, bytes],
|
command: str | bytes,
|
||||||
ignore_errors: bool = False,
|
ignore_errors: bool = False,
|
||||||
allow_warning: bool = True,
|
allow_warning: bool = True,
|
||||||
**parameters: Union[str, int, bool],
|
privileged: bool = False,
|
||||||
|
**parameters: Any,
|
||||||
) -> dict:
|
) -> dict:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -13,9 +13,11 @@
|
|||||||
# See the License for the specific language governing permissions and -
|
# See the License for the specific language governing permissions and -
|
||||||
# limitations under the License. -
|
# limitations under the License. -
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import json
|
import json
|
||||||
from typing import Union
|
from typing import Any
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
|
|
||||||
@@ -26,14 +28,16 @@ from pyasic.web import BaseWebAPI
|
|||||||
class AntminerModernWebAPI(BaseWebAPI):
|
class AntminerModernWebAPI(BaseWebAPI):
|
||||||
def __init__(self, ip: str) -> None:
|
def __init__(self, ip: str) -> None:
|
||||||
super().__init__(ip)
|
super().__init__(ip)
|
||||||
|
self.username = "root"
|
||||||
self.pwd = settings.get("default_antminer_web_password", "root")
|
self.pwd = settings.get("default_antminer_web_password", "root")
|
||||||
|
|
||||||
async def send_command(
|
async def send_command(
|
||||||
self,
|
self,
|
||||||
command: Union[str, bytes],
|
command: str | bytes,
|
||||||
ignore_errors: bool = False,
|
ignore_errors: bool = False,
|
||||||
allow_warning: bool = True,
|
allow_warning: bool = True,
|
||||||
**parameters: Union[str, int, bool],
|
privileged: bool = False,
|
||||||
|
**parameters: Any,
|
||||||
) -> dict:
|
) -> dict:
|
||||||
url = f"http://{self.ip}:{self.port}/cgi-bin/{command}.cgi"
|
url = f"http://{self.ip}:{self.port}/cgi-bin/{command}.cgi"
|
||||||
auth = httpx.DigestAuth(self.username, self.pwd)
|
auth = httpx.DigestAuth(self.username, self.pwd)
|
||||||
@@ -44,9 +48,9 @@ class AntminerModernWebAPI(BaseWebAPI):
|
|||||||
if parameters:
|
if parameters:
|
||||||
data = await client.post(
|
data = await client.post(
|
||||||
url,
|
url,
|
||||||
data=json.dumps(parameters),
|
|
||||||
auth=auth,
|
auth=auth,
|
||||||
timeout=settings.get("api_function_timeout", 3), # noqa
|
timeout=settings.get("api_function_timeout", 3),
|
||||||
|
json=parameters,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
data = await client.get(url, auth=auth)
|
data = await client.get(url, auth=auth)
|
||||||
@@ -76,7 +80,9 @@ class AntminerModernWebAPI(BaseWebAPI):
|
|||||||
data["multicommand"] = True
|
data["multicommand"] = True
|
||||||
return data
|
return data
|
||||||
|
|
||||||
async def _handle_multicommand(self, client: httpx.AsyncClient, command: str):
|
async def _handle_multicommand(
|
||||||
|
self, client: httpx.AsyncClient, command: str
|
||||||
|
) -> dict:
|
||||||
auth = httpx.DigestAuth(self.username, self.pwd)
|
auth = httpx.DigestAuth(self.username, self.pwd)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -142,14 +148,16 @@ class AntminerModernWebAPI(BaseWebAPI):
|
|||||||
class AntminerOldWebAPI(BaseWebAPI):
|
class AntminerOldWebAPI(BaseWebAPI):
|
||||||
def __init__(self, ip: str) -> None:
|
def __init__(self, ip: str) -> None:
|
||||||
super().__init__(ip)
|
super().__init__(ip)
|
||||||
|
self.username = "root"
|
||||||
self.pwd = settings.get("default_antminer_web_password", "root")
|
self.pwd = settings.get("default_antminer_web_password", "root")
|
||||||
|
|
||||||
async def send_command(
|
async def send_command(
|
||||||
self,
|
self,
|
||||||
command: Union[str, bytes],
|
command: str | bytes,
|
||||||
ignore_errors: bool = False,
|
ignore_errors: bool = False,
|
||||||
allow_warning: bool = True,
|
allow_warning: bool = True,
|
||||||
**parameters: Union[str, int, bool],
|
privileged: bool = False,
|
||||||
|
**parameters: Any,
|
||||||
) -> dict:
|
) -> dict:
|
||||||
url = f"http://{self.ip}:{self.port}/cgi-bin/{command}.cgi"
|
url = f"http://{self.ip}:{self.port}/cgi-bin/{command}.cgi"
|
||||||
auth = httpx.DigestAuth(self.username, self.pwd)
|
auth = httpx.DigestAuth(self.username, self.pwd)
|
||||||
|
|||||||
@@ -13,10 +13,12 @@
|
|||||||
# See the License for the specific language governing permissions and -
|
# See the License for the specific language governing permissions and -
|
||||||
# limitations under the License. -
|
# limitations under the License. -
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import json
|
import json
|
||||||
import warnings
|
import warnings
|
||||||
from typing import Any, List, Union
|
from typing import Any
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
|
|
||||||
@@ -31,9 +33,9 @@ class FluxWebAPI(BaseWebAPI):
|
|||||||
self.username = "admin"
|
self.username = "admin"
|
||||||
self.pwd = settings.get("default_auradine_web_password", "admin")
|
self.pwd = settings.get("default_auradine_web_password", "admin")
|
||||||
self.port = 8080
|
self.port = 8080
|
||||||
self.jwt = None
|
self.token = None
|
||||||
|
|
||||||
async def auth(self):
|
async def auth(self) -> str | None:
|
||||||
async with httpx.AsyncClient(transport=settings.transport()) as client:
|
async with httpx.AsyncClient(transport=settings.transport()) as client:
|
||||||
try:
|
try:
|
||||||
auth = await client.post(
|
auth = await client.post(
|
||||||
@@ -49,20 +51,24 @@ class FluxWebAPI(BaseWebAPI):
|
|||||||
else:
|
else:
|
||||||
json_auth = auth.json()
|
json_auth = auth.json()
|
||||||
try:
|
try:
|
||||||
self.jwt = json_auth["Token"][0]["Token"]
|
self.token = json_auth["Token"][0]["Token"]
|
||||||
except LookupError:
|
except LookupError:
|
||||||
return None
|
return None
|
||||||
return self.jwt
|
return self.token
|
||||||
|
|
||||||
async def send_command(
|
async def send_command(
|
||||||
self,
|
self,
|
||||||
command: Union[str, bytes],
|
command: str | bytes,
|
||||||
post: bool = False,
|
|
||||||
ignore_errors: bool = False,
|
ignore_errors: bool = False,
|
||||||
allow_warning: bool = True,
|
allow_warning: bool = True,
|
||||||
|
privileged: bool = False,
|
||||||
**parameters: Any,
|
**parameters: Any,
|
||||||
) -> dict:
|
) -> dict:
|
||||||
if self.jwt is None:
|
post = privileged or not parameters == {}
|
||||||
|
if not parameters == {}:
|
||||||
|
parameters["command"] = command
|
||||||
|
|
||||||
|
if self.token is None:
|
||||||
await self.auth()
|
await self.auth()
|
||||||
async with httpx.AsyncClient(transport=settings.transport()) as client:
|
async with httpx.AsyncClient(transport=settings.transport()) as client:
|
||||||
for i in range(settings.get("get_data_retries", 1)):
|
for i in range(settings.get("get_data_retries", 1)):
|
||||||
@@ -70,20 +76,14 @@ class FluxWebAPI(BaseWebAPI):
|
|||||||
if post:
|
if post:
|
||||||
response = await client.post(
|
response = await client.post(
|
||||||
f"http://{self.ip}:{self.port}/{command}",
|
f"http://{self.ip}:{self.port}/{command}",
|
||||||
headers={"Token": self.jwt},
|
headers={"Token": self.token},
|
||||||
timeout=settings.get("api_function_timeout", 5),
|
timeout=settings.get("api_function_timeout", 5),
|
||||||
)
|
json=parameters,
|
||||||
elif parameters:
|
|
||||||
response = await client.post(
|
|
||||||
f"http://{self.ip}:{self.port}/{command}",
|
|
||||||
headers={"Token": self.jwt},
|
|
||||||
timeout=settings.get("api_function_timeout", 5),
|
|
||||||
json={"command": command, **parameters},
|
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
response = await client.get(
|
response = await client.get(
|
||||||
f"http://{self.ip}:{self.port}/{command}",
|
f"http://{self.ip}:{self.port}/{command}",
|
||||||
headers={"Token": self.jwt},
|
headers={"Token": self.token},
|
||||||
timeout=settings.get("api_function_timeout", 5),
|
timeout=settings.get("api_function_timeout", 5),
|
||||||
)
|
)
|
||||||
json_data = response.json()
|
json_data = response.json()
|
||||||
@@ -95,9 +95,7 @@ class FluxWebAPI(BaseWebAPI):
|
|||||||
await self.auth()
|
await self.auth()
|
||||||
continue
|
continue
|
||||||
return json_data
|
return json_data
|
||||||
except httpx.HTTPError:
|
except (httpx.HTTPError, json.JSONDecodeError):
|
||||||
pass
|
|
||||||
except json.JSONDecodeError:
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
async def multicommand(
|
async def multicommand(
|
||||||
@@ -166,97 +164,97 @@ class FluxWebAPI(BaseWebAPI):
|
|||||||
return False, data["STATUS"][0]["Msg"]
|
return False, data["STATUS"][0]["Msg"]
|
||||||
return True, None
|
return True, None
|
||||||
|
|
||||||
async def factory_reset(self):
|
async def factory_reset(self) -> dict:
|
||||||
return await self.send_command("factory-reset", post=True)
|
return await self.send_command("factory-reset", privileged=True)
|
||||||
|
|
||||||
async def get_fan(self):
|
async def get_fan(self) -> dict:
|
||||||
return await self.send_command("fan")
|
return await self.send_command("fan")
|
||||||
|
|
||||||
async def set_fan(self, fan: int, speed_pct: int):
|
async def set_fan(self, fan: int, speed_pct: int) -> dict:
|
||||||
return await self.send_command("fan", index=fan, percentage=speed_pct)
|
return await self.send_command("fan", index=fan, percentage=speed_pct)
|
||||||
|
|
||||||
async def firmware_upgrade(self, url: str = None, version: str = "latest"):
|
async def firmware_upgrade(self, url: str = None, version: str = "latest") -> dict:
|
||||||
if url is not None:
|
if url is not None:
|
||||||
return await self.send_command("firmware-upgrade", url=url)
|
return await self.send_command("firmware-upgrade", url=url)
|
||||||
return await self.send_command("firmware-upgrade", version=version)
|
return await self.send_command("firmware-upgrade", version=version)
|
||||||
|
|
||||||
async def get_frequency(self):
|
async def get_frequency(self) -> dict:
|
||||||
return await self.send_command("frequency")
|
return await self.send_command("frequency")
|
||||||
|
|
||||||
async def set_frequency(self, board: int, frequency: float):
|
async def set_frequency(self, board: int, frequency: float) -> dict:
|
||||||
return await self.send_command("frequency", board=board, frequency=frequency)
|
return await self.send_command("frequency", board=board, frequency=frequency)
|
||||||
|
|
||||||
async def ipreport(self):
|
async def ipreport(self) -> dict:
|
||||||
return await self.send_command("ipreport")
|
return await self.send_command("ipreport")
|
||||||
|
|
||||||
async def get_led(self):
|
async def get_led(self) -> dict:
|
||||||
return await self.send_command("led")
|
return await self.send_command("led")
|
||||||
|
|
||||||
async def set_led(self, code: int):
|
async def set_led(self, code: int) -> dict:
|
||||||
return await self.send_command("led", code=code)
|
return await self.send_command("led", code=code)
|
||||||
|
|
||||||
async def set_led_custom(self, code: int, led_1: int, led_2: int, msg: str):
|
async def set_led_custom(self, code: int, led_1: int, led_2: int, msg: str) -> dict:
|
||||||
return await self.send_command(
|
return await self.send_command(
|
||||||
"led", code=code, led1=led_1, led2=led_2, msg=msg
|
"led", code=code, led1=led_1, led2=led_2, msg=msg
|
||||||
)
|
)
|
||||||
|
|
||||||
async def get_mode(self):
|
async def get_mode(self) -> dict:
|
||||||
return await self.send_command("mode")
|
return await self.send_command("mode")
|
||||||
|
|
||||||
async def set_mode(self, **kwargs):
|
async def set_mode(self, **kwargs) -> dict:
|
||||||
return await self.send_command("mode", **kwargs)
|
return await self.send_command("mode", **kwargs)
|
||||||
|
|
||||||
async def get_network(self):
|
async def get_network(self) -> dict:
|
||||||
return await self.send_command("network")
|
return await self.send_command("network")
|
||||||
|
|
||||||
async def set_network(self, **kwargs):
|
async def set_network(self, **kwargs) -> dict:
|
||||||
return await self.send_command("network", **kwargs)
|
return await self.send_command("network", **kwargs)
|
||||||
|
|
||||||
async def password(self, password: str):
|
async def password(self, password: str) -> dict:
|
||||||
res = await self.send_command(
|
res = await self.send_command(
|
||||||
"password", user=self.username, old=self.pwd, new=password
|
"password", user=self.username, old=self.pwd, new=password
|
||||||
)
|
)
|
||||||
self.pwd = password
|
self.pwd = password
|
||||||
return res
|
return res
|
||||||
|
|
||||||
async def get_psu(self):
|
async def get_psu(self) -> dict:
|
||||||
return await self.send_command("psu")
|
return await self.send_command("psu")
|
||||||
|
|
||||||
async def set_psu(self, voltage: float):
|
async def set_psu(self, voltage: float) -> dict:
|
||||||
return await self.send_command("psu", voltage=voltage)
|
return await self.send_command("psu", voltage=voltage)
|
||||||
|
|
||||||
async def get_register(self):
|
async def get_register(self) -> dict:
|
||||||
return await self.send_command("register")
|
return await self.send_command("register")
|
||||||
|
|
||||||
async def set_register(self, company: str):
|
async def set_register(self, company: str) -> dict:
|
||||||
return await self.send_command("register", parameter=company)
|
return await self.send_command("register", parameter=company)
|
||||||
|
|
||||||
async def reboot(self):
|
async def reboot(self) -> dict:
|
||||||
return await self.send_command("restart", post=True)
|
return await self.send_command("restart", privileged=True)
|
||||||
|
|
||||||
async def restart_gcminer(self):
|
async def restart_gcminer(self) -> dict:
|
||||||
return await self.send_command("restart", parameter="gcminer")
|
return await self.send_command("restart", parameter="gcminer")
|
||||||
|
|
||||||
async def restart_api_server(self):
|
async def restart_api_server(self) -> dict:
|
||||||
return await self.send_command("restart", parameter="api-server")
|
return await self.send_command("restart", parameter="api-server")
|
||||||
|
|
||||||
async def temperature(self):
|
async def temperature(self) -> dict:
|
||||||
return await self.send_command("temperature")
|
return await self.send_command("temperature")
|
||||||
|
|
||||||
async def timedate(self, ntp: str, timezone: str):
|
async def timedate(self, ntp: str, timezone: str) -> dict:
|
||||||
return await self.send_command("timedate", ntp=ntp, timezone=timezone)
|
return await self.send_command("timedate", ntp=ntp, timezone=timezone)
|
||||||
|
|
||||||
async def token(self):
|
async def token(self) -> dict:
|
||||||
return await self.send_command("token", user=self.username, password=self.pwd)
|
return await self.send_command("token", user=self.username, password=self.pwd)
|
||||||
|
|
||||||
async def update_pools(self, pools: List[dict]):
|
async def update_pools(self, pools: list[dict]) -> dict:
|
||||||
return await self.send_command("updatepools", pools=pools)
|
return await self.send_command("updatepools", pools=pools)
|
||||||
|
|
||||||
async def voltage(self):
|
async def voltage(self) -> dict:
|
||||||
return await self.send_command("voltage")
|
return await self.send_command("voltage")
|
||||||
|
|
||||||
async def get_ztp(self):
|
async def get_ztp(self) -> dict:
|
||||||
return await self.send_command("ztp")
|
return await self.send_command("ztp")
|
||||||
|
|
||||||
async def set_ztp(self, enable: bool):
|
async def set_ztp(self, enable: bool) -> dict:
|
||||||
return await self.send_command("ztp", parameter="on" if enable else "off")
|
return await self.send_command("ztp", parameter="on" if enable else "off")
|
||||||
|
|||||||
@@ -1,149 +1,2 @@
|
|||||||
# ------------------------------------------------------------------------------
|
from .boser import BOSerWebAPI
|
||||||
# Copyright 2022 Upstream Data Inc -
|
from .bosminer import BOSMinerWebAPI
|
||||||
# -
|
|
||||||
# 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. -
|
|
||||||
# ------------------------------------------------------------------------------
|
|
||||||
import asyncio
|
|
||||||
from typing import Union
|
|
||||||
|
|
||||||
from pyasic import settings
|
|
||||||
from pyasic.errors import APIError
|
|
||||||
from pyasic.web import BaseWebAPI
|
|
||||||
|
|
||||||
from .graphql import BOSerGraphQLAPI
|
|
||||||
from .grpc import BOSerGRPCAPI
|
|
||||||
from .luci import BOSMinerLuCIAPI
|
|
||||||
|
|
||||||
|
|
||||||
class BOSMinerWebAPI(BaseWebAPI):
|
|
||||||
def __init__(self, ip: str) -> None:
|
|
||||||
self.luci = BOSMinerLuCIAPI(
|
|
||||||
ip, settings.get("default_bosminer_password", "root")
|
|
||||||
)
|
|
||||||
self._pwd = settings.get("default_bosminer_password", "root")
|
|
||||||
self._port = 80
|
|
||||||
super().__init__(ip)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def pwd(self):
|
|
||||||
return self._pwd
|
|
||||||
|
|
||||||
@pwd.setter
|
|
||||||
def pwd(self, other: str):
|
|
||||||
self._pwd = other
|
|
||||||
self.luci.pwd = other
|
|
||||||
|
|
||||||
@property
|
|
||||||
def port(self):
|
|
||||||
return self._port
|
|
||||||
|
|
||||||
@port.setter
|
|
||||||
def port(self, other: str):
|
|
||||||
self._port = other
|
|
||||||
self.luci.port = other
|
|
||||||
|
|
||||||
async def send_command(
|
|
||||||
self,
|
|
||||||
command: Union[str, dict],
|
|
||||||
ignore_errors: bool = False,
|
|
||||||
allow_warning: bool = True,
|
|
||||||
**parameters: Union[str, int, bool],
|
|
||||||
) -> dict:
|
|
||||||
return await self.luci.send_command(command)
|
|
||||||
|
|
||||||
async def multicommand(
|
|
||||||
self, *commands: Union[dict, str], allow_warning: bool = True
|
|
||||||
) -> dict:
|
|
||||||
return await self.luci.multicommand(*commands)
|
|
||||||
|
|
||||||
|
|
||||||
class BOSerWebAPI(BOSMinerWebAPI):
|
|
||||||
def __init__(self, ip: str) -> None:
|
|
||||||
self.gql = BOSerGraphQLAPI(
|
|
||||||
ip, settings.get("default_bosminer_password", "root")
|
|
||||||
)
|
|
||||||
self.grpc = BOSerGRPCAPI(ip, settings.get("default_bosminer_password", "root"))
|
|
||||||
self._port = 80
|
|
||||||
super().__init__(ip)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def pwd(self):
|
|
||||||
return self._pwd
|
|
||||||
|
|
||||||
@pwd.setter
|
|
||||||
def pwd(self, other: str):
|
|
||||||
self._pwd = other
|
|
||||||
self.luci.pwd = other
|
|
||||||
self.gql.pwd = other
|
|
||||||
self.grpc.pwd = other
|
|
||||||
|
|
||||||
@property
|
|
||||||
def port(self):
|
|
||||||
return self._port
|
|
||||||
|
|
||||||
@port.setter
|
|
||||||
def port(self, other: str):
|
|
||||||
self._port = other
|
|
||||||
self.luci.port = other
|
|
||||||
self.gql.port = other
|
|
||||||
|
|
||||||
async def send_command(
|
|
||||||
self,
|
|
||||||
command: Union[str, dict],
|
|
||||||
ignore_errors: bool = False,
|
|
||||||
allow_warning: bool = True,
|
|
||||||
**parameters: Union[str, int, bool],
|
|
||||||
) -> dict:
|
|
||||||
command_type = self.select_command_type(command)
|
|
||||||
if command_type == "gql":
|
|
||||||
return await self.gql.send_command(command)
|
|
||||||
elif command_type == "grpc":
|
|
||||||
try:
|
|
||||||
return await getattr(self.grpc, command.replace("grpc_", ""))()
|
|
||||||
except AttributeError:
|
|
||||||
raise APIError(f"No gRPC command found for command: {command}")
|
|
||||||
elif command_type == "luci":
|
|
||||||
return await self.luci.send_command(command)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def select_command_type(command: Union[str, dict]) -> str:
|
|
||||||
if isinstance(command, dict):
|
|
||||||
return "gql"
|
|
||||||
else:
|
|
||||||
return "grpc"
|
|
||||||
|
|
||||||
async def multicommand(
|
|
||||||
self, *commands: Union[dict, str], allow_warning: bool = True
|
|
||||||
) -> dict:
|
|
||||||
cmd_types = {"grpc": [], "gql": []}
|
|
||||||
for cmd in commands:
|
|
||||||
cmd_types[self.select_command_type(cmd)].append(cmd)
|
|
||||||
|
|
||||||
async def no_op():
|
|
||||||
return {}
|
|
||||||
|
|
||||||
if len(cmd_types["grpc"]) > 0:
|
|
||||||
grpc_data_t = asyncio.create_task(
|
|
||||||
self.grpc.multicommand(*cmd_types["grpc"])
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
grpc_data_t = asyncio.create_task(no_op())
|
|
||||||
if len(cmd_types["gql"]) > 0:
|
|
||||||
gql_data_t = asyncio.create_task(self.gql.multicommand(*cmd_types["gql"]))
|
|
||||||
else:
|
|
||||||
gql_data_t = asyncio.create_task(no_op())
|
|
||||||
|
|
||||||
await asyncio.gather(grpc_data_t, gql_data_t)
|
|
||||||
|
|
||||||
data = dict(**grpc_data_t.result(), **gql_data_t.result())
|
|
||||||
return data
|
|
||||||
|
|||||||
@@ -13,15 +13,19 @@
|
|||||||
# See the License for the specific language governing permissions and -
|
# See the License for the specific language governing permissions and -
|
||||||
# limitations under the License. -
|
# limitations under the License. -
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from betterproto import Message
|
|
||||||
from grpclib import GRPCError, Status
|
from grpclib import GRPCError, Status
|
||||||
from grpclib.client import Channel
|
from grpclib.client import Channel
|
||||||
|
|
||||||
|
from pyasic import settings
|
||||||
from pyasic.errors import APIError
|
from pyasic.errors import APIError
|
||||||
|
from pyasic.web import BaseWebAPI
|
||||||
|
|
||||||
from .proto.braiins.bos import *
|
from .proto.braiins.bos import *
|
||||||
from .proto.braiins.bos.v1 import *
|
from .proto.braiins.bos.v1 import *
|
||||||
@@ -41,14 +45,13 @@ class BOSMinerGRPCStub(
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class BOSerGRPCAPI:
|
class BOSerWebAPI(BaseWebAPI):
|
||||||
def __init__(self, ip: str, pwd: str):
|
def __init__(self, ip: str) -> None:
|
||||||
self.ip = ip
|
super().__init__(ip)
|
||||||
self.username = "root"
|
self.username = "root"
|
||||||
self.pwd = pwd
|
self.pwd = settings.get("default_bosminer_password", "root")
|
||||||
self.port = 50051
|
self.port = 50051
|
||||||
self._auth = None
|
self._auth_time = None
|
||||||
self._auth_time = datetime.now()
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def commands(self) -> list:
|
def commands(self) -> list:
|
||||||
@@ -85,13 +88,15 @@ class BOSerGRPCAPI:
|
|||||||
|
|
||||||
async def send_command(
|
async def send_command(
|
||||||
self,
|
self,
|
||||||
command: str,
|
command: str | bytes,
|
||||||
message: Message = None,
|
|
||||||
ignore_errors: bool = False,
|
ignore_errors: bool = False,
|
||||||
auth: bool = True,
|
allow_warning: bool = True,
|
||||||
|
privileged: bool = False,
|
||||||
|
**parameters: Any,
|
||||||
) -> dict:
|
) -> dict:
|
||||||
|
message: betterproto.Message = parameters["message"]
|
||||||
metadata = []
|
metadata = []
|
||||||
if auth:
|
if privileged:
|
||||||
metadata.append(("authorization", await self.auth()))
|
metadata.append(("authorization", await self.auth()))
|
||||||
try:
|
try:
|
||||||
async with Channel(self.ip, self.port) as c:
|
async with Channel(self.ip, self.port) as c:
|
||||||
@@ -111,15 +116,15 @@ class BOSerGRPCAPI:
|
|||||||
except GRPCError as e:
|
except GRPCError as e:
|
||||||
raise APIError(f"gRPC command failed - {endpoint}") from e
|
raise APIError(f"gRPC command failed - {endpoint}") from e
|
||||||
|
|
||||||
async def auth(self):
|
async def auth(self) -> str | None:
|
||||||
if self._auth is not None and self._auth_time - datetime.now() < timedelta(
|
if self.token is not None and self._auth_time - datetime.now() < timedelta(
|
||||||
seconds=3540
|
seconds=3540
|
||||||
):
|
):
|
||||||
return self._auth
|
return self.token
|
||||||
await self._get_auth()
|
await self._get_auth()
|
||||||
return self._auth
|
return self.token
|
||||||
|
|
||||||
async def _get_auth(self):
|
async def _get_auth(self) -> str:
|
||||||
async with Channel(self.ip, self.port) as c:
|
async with Channel(self.ip, self.port) as c:
|
||||||
req = LoginRequest(username=self.username, password=self.pwd)
|
req = LoginRequest(username=self.username, password=self.pwd)
|
||||||
async with c.request(
|
async with c.request(
|
||||||
@@ -132,74 +137,79 @@ class BOSerGRPCAPI:
|
|||||||
await stream.recv_initial_metadata()
|
await stream.recv_initial_metadata()
|
||||||
auth = stream.initial_metadata.get("authorization")
|
auth = stream.initial_metadata.get("authorization")
|
||||||
if auth is not None:
|
if auth is not None:
|
||||||
self._auth = auth
|
self.token = auth
|
||||||
self._auth_time = datetime.now()
|
self._auth_time = datetime.now()
|
||||||
return self._auth
|
return self.token
|
||||||
|
|
||||||
async def get_api_version(self):
|
async def get_api_version(self) -> dict:
|
||||||
return await self.send_command(
|
return await self.send_command(
|
||||||
"get_api_version", ApiVersionRequest(), auth=False
|
"get_api_version", message=ApiVersionRequest(), privileged=False
|
||||||
)
|
)
|
||||||
|
|
||||||
async def start(self):
|
async def start(self) -> dict:
|
||||||
return await self.send_command("start", StartRequest())
|
return await self.send_command("start", message=StartRequest())
|
||||||
|
|
||||||
async def stop(self):
|
async def stop(self) -> dict:
|
||||||
return await self.send_command("stop", StopRequest())
|
return await self.send_command("stop", message=StopRequest())
|
||||||
|
|
||||||
async def pause_mining(self):
|
async def pause_mining(self) -> dict:
|
||||||
return await self.send_command("pause_mining", PauseMiningRequest())
|
return await self.send_command("pause_mining", message=PauseMiningRequest())
|
||||||
|
|
||||||
async def resume_mining(self):
|
async def resume_mining(self) -> dict:
|
||||||
return await self.send_command("resume_mining", ResumeMiningRequest())
|
return await self.send_command("resume_mining", message=ResumeMiningRequest())
|
||||||
|
|
||||||
async def restart(self):
|
async def restart(self) -> dict:
|
||||||
return await self.send_command("restart", RestartRequest())
|
return await self.send_command("restart", message=RestartRequest())
|
||||||
|
|
||||||
async def reboot(self):
|
async def reboot(self) -> dict:
|
||||||
return await self.send_command("reboot", RebootRequest())
|
return await self.send_command("reboot", message=RebootRequest())
|
||||||
|
|
||||||
async def set_locate_device_status(self, enable: bool):
|
async def set_locate_device_status(self, enable: bool) -> dict:
|
||||||
return await self.send_command(
|
return await self.send_command(
|
||||||
"set_locate_device_status", SetLocateDeviceStatusRequest(enable=enable)
|
"set_locate_device_status",
|
||||||
|
message=SetLocateDeviceStatusRequest(enable=enable),
|
||||||
)
|
)
|
||||||
|
|
||||||
async def get_locate_device_status(self):
|
async def get_locate_device_status(self) -> dict:
|
||||||
return await self.send_command(
|
return await self.send_command(
|
||||||
"get_locate_device_status", GetLocateDeviceStatusRequest()
|
"get_locate_device_status", message=GetLocateDeviceStatusRequest()
|
||||||
)
|
)
|
||||||
|
|
||||||
async def set_password(self, password: str = None):
|
async def set_password(self, password: str = None) -> dict:
|
||||||
return await self.send_command(
|
return await self.send_command(
|
||||||
"set_password", SetPasswordRequest(password=password)
|
"set_password", message=SetPasswordRequest(password=password)
|
||||||
)
|
)
|
||||||
|
|
||||||
async def get_cooling_state(self):
|
async def get_cooling_state(self) -> dict:
|
||||||
return await self.send_command("get_cooling_state", GetCoolingStateRequest())
|
return await self.send_command(
|
||||||
|
"get_cooling_state", message=GetCoolingStateRequest()
|
||||||
|
)
|
||||||
|
|
||||||
async def set_immersion_mode(
|
async def set_immersion_mode(
|
||||||
self,
|
self,
|
||||||
enable: bool,
|
enable: bool,
|
||||||
save_action: SaveAction = SaveAction.SAVE_ACTION_SAVE_AND_APPLY,
|
save_action: SaveAction = SaveAction.SAVE_ACTION_SAVE_AND_APPLY,
|
||||||
):
|
) -> dict:
|
||||||
return await self.send_command(
|
return await self.send_command(
|
||||||
"set_immersion_mode",
|
"set_immersion_mode",
|
||||||
SetImmersionModeRequest(
|
message=SetImmersionModeRequest(
|
||||||
enable_immersion_mode=enable, save_action=save_action
|
enable_immersion_mode=enable, save_action=save_action
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
async def get_tuner_state(self):
|
async def get_tuner_state(self) -> dict:
|
||||||
return await self.send_command("get_tuner_state", GetTunerStateRequest())
|
|
||||||
|
|
||||||
async def list_target_profiles(self):
|
|
||||||
return await self.send_command(
|
return await self.send_command(
|
||||||
"list_target_profiles", ListTargetProfilesRequest()
|
"get_tuner_state", message=GetTunerStateRequest()
|
||||||
|
)
|
||||||
|
|
||||||
|
async def list_target_profiles(self) -> dict:
|
||||||
|
return await self.send_command(
|
||||||
|
"list_target_profiles", message=ListTargetProfilesRequest()
|
||||||
)
|
)
|
||||||
|
|
||||||
async def set_default_power_target(
|
async def set_default_power_target(
|
||||||
self, save_action: SaveAction = SaveAction.SAVE_ACTION_SAVE_AND_APPLY
|
self, save_action: SaveAction = SaveAction.SAVE_ACTION_SAVE_AND_APPLY
|
||||||
):
|
) -> dict:
|
||||||
return await self.send_command(
|
return await self.send_command(
|
||||||
"set_default_power_target",
|
"set_default_power_target",
|
||||||
message=SetDefaultPowerTargetRequest(save_action=save_action),
|
message=SetDefaultPowerTargetRequest(save_action=save_action),
|
||||||
@@ -209,10 +219,10 @@ class BOSerGRPCAPI:
|
|||||||
self,
|
self,
|
||||||
power_target: int,
|
power_target: int,
|
||||||
save_action: SaveAction = SaveAction.SAVE_ACTION_SAVE_AND_APPLY,
|
save_action: SaveAction = SaveAction.SAVE_ACTION_SAVE_AND_APPLY,
|
||||||
):
|
) -> dict:
|
||||||
return await self.send_command(
|
return await self.send_command(
|
||||||
"set_power_target",
|
"set_power_target",
|
||||||
SetPowerTargetRequest(
|
message=SetPowerTargetRequest(
|
||||||
power_target=Power(watt=power_target), save_action=save_action
|
power_target=Power(watt=power_target), save_action=save_action
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@@ -221,7 +231,7 @@ class BOSerGRPCAPI:
|
|||||||
self,
|
self,
|
||||||
power_target_increment: int,
|
power_target_increment: int,
|
||||||
save_action: SaveAction = SaveAction.SAVE_ACTION_SAVE_AND_APPLY,
|
save_action: SaveAction = SaveAction.SAVE_ACTION_SAVE_AND_APPLY,
|
||||||
):
|
) -> dict:
|
||||||
return await self.send_command(
|
return await self.send_command(
|
||||||
"increment_power_target",
|
"increment_power_target",
|
||||||
message=IncrementPowerTargetRequest(
|
message=IncrementPowerTargetRequest(
|
||||||
@@ -234,7 +244,7 @@ class BOSerGRPCAPI:
|
|||||||
self,
|
self,
|
||||||
power_target_decrement: int,
|
power_target_decrement: int,
|
||||||
save_action: SaveAction = SaveAction.SAVE_ACTION_SAVE_AND_APPLY,
|
save_action: SaveAction = SaveAction.SAVE_ACTION_SAVE_AND_APPLY,
|
||||||
):
|
) -> dict:
|
||||||
return await self.send_command(
|
return await self.send_command(
|
||||||
"decrement_power_target",
|
"decrement_power_target",
|
||||||
message=DecrementPowerTargetRequest(
|
message=DecrementPowerTargetRequest(
|
||||||
@@ -245,7 +255,7 @@ class BOSerGRPCAPI:
|
|||||||
|
|
||||||
async def set_default_hashrate_target(
|
async def set_default_hashrate_target(
|
||||||
self, save_action: SaveAction = SaveAction.SAVE_ACTION_SAVE_AND_APPLY
|
self, save_action: SaveAction = SaveAction.SAVE_ACTION_SAVE_AND_APPLY
|
||||||
):
|
) -> dict:
|
||||||
return await self.send_command(
|
return await self.send_command(
|
||||||
"set_default_hashrate_target",
|
"set_default_hashrate_target",
|
||||||
message=SetDefaultHashrateTargetRequest(save_action=save_action),
|
message=SetDefaultHashrateTargetRequest(save_action=save_action),
|
||||||
@@ -255,10 +265,10 @@ class BOSerGRPCAPI:
|
|||||||
self,
|
self,
|
||||||
hashrate_target: float,
|
hashrate_target: float,
|
||||||
save_action: SaveAction = SaveAction.SAVE_ACTION_SAVE_AND_APPLY,
|
save_action: SaveAction = SaveAction.SAVE_ACTION_SAVE_AND_APPLY,
|
||||||
):
|
) -> dict:
|
||||||
return await self.send_command(
|
return await self.send_command(
|
||||||
"set_hashrate_target",
|
"set_hashrate_target",
|
||||||
SetHashrateTargetRequest(
|
message=SetHashrateTargetRequest(
|
||||||
hashrate_target=TeraHashrate(terahash_per_second=hashrate_target),
|
hashrate_target=TeraHashrate(terahash_per_second=hashrate_target),
|
||||||
save_action=save_action,
|
save_action=save_action,
|
||||||
),
|
),
|
||||||
@@ -268,10 +278,10 @@ class BOSerGRPCAPI:
|
|||||||
self,
|
self,
|
||||||
hashrate_target_increment: int,
|
hashrate_target_increment: int,
|
||||||
save_action: SaveAction = SaveAction.SAVE_ACTION_SAVE_AND_APPLY,
|
save_action: SaveAction = SaveAction.SAVE_ACTION_SAVE_AND_APPLY,
|
||||||
):
|
) -> dict:
|
||||||
return await self.send_command(
|
return await self.send_command(
|
||||||
"increment_hashrate_target",
|
"increment_hashrate_target",
|
||||||
IncrementHashrateTargetRequest(
|
message=IncrementHashrateTargetRequest(
|
||||||
hashrate_target_increment=TeraHashrate(
|
hashrate_target_increment=TeraHashrate(
|
||||||
terahash_per_second=hashrate_target_increment
|
terahash_per_second=hashrate_target_increment
|
||||||
),
|
),
|
||||||
@@ -283,10 +293,10 @@ class BOSerGRPCAPI:
|
|||||||
self,
|
self,
|
||||||
hashrate_target_decrement: int,
|
hashrate_target_decrement: int,
|
||||||
save_action: SaveAction = SaveAction.SAVE_ACTION_SAVE_AND_APPLY,
|
save_action: SaveAction = SaveAction.SAVE_ACTION_SAVE_AND_APPLY,
|
||||||
):
|
) -> dict:
|
||||||
return await self.send_command(
|
return await self.send_command(
|
||||||
"decrement_hashrate_target",
|
"decrement_hashrate_target",
|
||||||
DecrementHashrateTargetRequest(
|
message=DecrementHashrateTargetRequest(
|
||||||
hashrate_target_decrement=TeraHashrate(
|
hashrate_target_decrement=TeraHashrate(
|
||||||
terahash_per_second=hashrate_target_decrement
|
terahash_per_second=hashrate_target_decrement
|
||||||
),
|
),
|
||||||
@@ -301,7 +311,7 @@ class BOSerGRPCAPI:
|
|||||||
min_power_target: int,
|
min_power_target: int,
|
||||||
enable_shutdown: bool = None,
|
enable_shutdown: bool = None,
|
||||||
shutdown_duration: int = None,
|
shutdown_duration: int = None,
|
||||||
):
|
) -> dict:
|
||||||
return await self.send_command(
|
return await self.send_command(
|
||||||
"set_dps",
|
"set_dps",
|
||||||
message=SetDpsRequest(
|
message=SetDpsRequest(
|
||||||
@@ -322,7 +332,7 @@ class BOSerGRPCAPI:
|
|||||||
wattage_target: int = None,
|
wattage_target: int = None,
|
||||||
hashrate_target: int = None,
|
hashrate_target: int = None,
|
||||||
save_action: SaveAction = SaveAction.SAVE_ACTION_SAVE_AND_APPLY,
|
save_action: SaveAction = SaveAction.SAVE_ACTION_SAVE_AND_APPLY,
|
||||||
):
|
) -> dict:
|
||||||
if wattage_target is not None and hashrate_target is not None:
|
if wattage_target is not None and hashrate_target is not None:
|
||||||
logging.error(
|
logging.error(
|
||||||
"Cannot use both wattage_target and hashrate_target, using wattage_target."
|
"Cannot use both wattage_target and hashrate_target, using wattage_target."
|
||||||
@@ -362,62 +372,71 @@ class BOSerGRPCAPI:
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
async def get_active_performance_mode(self):
|
async def get_active_performance_mode(self) -> dict:
|
||||||
return await self.send_command(
|
return await self.send_command(
|
||||||
"get_active_performance_mode", GetPerformanceModeRequest()
|
"get_active_performance_mode", message=GetPerformanceModeRequest()
|
||||||
)
|
)
|
||||||
|
|
||||||
async def get_pool_groups(self):
|
async def get_pool_groups(self) -> dict:
|
||||||
return await self.send_command("get_pool_groups", GetPoolGroupsRequest())
|
|
||||||
|
|
||||||
async def create_pool_group(self):
|
|
||||||
raise NotImplementedError
|
|
||||||
return await self.send_command("braiins.bos.v1.PoolService/CreatePoolGroup")
|
|
||||||
|
|
||||||
async def update_pool_group(self):
|
|
||||||
raise NotImplementedError
|
|
||||||
return await self.send_command("braiins.bos.v1.PoolService/UpdatePoolGroup")
|
|
||||||
|
|
||||||
async def remove_pool_group(self):
|
|
||||||
raise NotImplementedError
|
|
||||||
return await self.send_command("braiins.bos.v1.PoolService/RemovePoolGroup")
|
|
||||||
|
|
||||||
async def get_miner_configuration(self):
|
|
||||||
return await self.send_command(
|
return await self.send_command(
|
||||||
"get_miner_configuration", GetMinerConfigurationRequest()
|
"get_pool_groups", message=GetPoolGroupsRequest()
|
||||||
)
|
)
|
||||||
|
|
||||||
async def get_constraints(self):
|
async def create_pool_group(self) -> dict:
|
||||||
return await self.send_command("get_constraints", GetConstraintsRequest())
|
raise NotImplementedError
|
||||||
|
|
||||||
async def get_license_state(self):
|
async def update_pool_group(self) -> dict:
|
||||||
return await self.send_command("get_license_state", GetLicenseStateRequest())
|
raise NotImplementedError
|
||||||
|
|
||||||
async def get_miner_status(self):
|
async def remove_pool_group(self) -> dict:
|
||||||
return await self.send_command("get_miner_status", GetMinerStatusRequest())
|
raise NotImplementedError
|
||||||
|
|
||||||
async def get_miner_details(self):
|
async def get_miner_configuration(self) -> dict:
|
||||||
return await self.send_command("get_miner_details", GetMinerDetailsRequest())
|
|
||||||
|
|
||||||
async def get_miner_stats(self):
|
|
||||||
return await self.send_command("get_miner_stats", GetMinerStatsRequest())
|
|
||||||
|
|
||||||
async def get_hashboards(self):
|
|
||||||
return await self.send_command("get_hashboards", GetHashboardsRequest())
|
|
||||||
|
|
||||||
async def get_support_archive(self):
|
|
||||||
return await self.send_command(
|
return await self.send_command(
|
||||||
"get_support_archive", GetSupportArchiveRequest()
|
"get_miner_configuration", message=GetMinerConfigurationRequest()
|
||||||
|
)
|
||||||
|
|
||||||
|
async def get_constraints(self) -> dict:
|
||||||
|
return await self.send_command(
|
||||||
|
"get_constraints", message=GetConstraintsRequest()
|
||||||
|
)
|
||||||
|
|
||||||
|
async def get_license_state(self) -> dict:
|
||||||
|
return await self.send_command(
|
||||||
|
"get_license_state", message=GetLicenseStateRequest()
|
||||||
|
)
|
||||||
|
|
||||||
|
async def get_miner_status(self) -> dict:
|
||||||
|
return await self.send_command(
|
||||||
|
"get_miner_status", message=GetMinerStatusRequest()
|
||||||
|
)
|
||||||
|
|
||||||
|
async def get_miner_details(self) -> dict:
|
||||||
|
return await self.send_command(
|
||||||
|
"get_miner_details", message=GetMinerDetailsRequest()
|
||||||
|
)
|
||||||
|
|
||||||
|
async def get_miner_stats(self) -> dict:
|
||||||
|
return await self.send_command(
|
||||||
|
"get_miner_stats", message=GetMinerStatsRequest()
|
||||||
|
)
|
||||||
|
|
||||||
|
async def get_hashboards(self) -> dict:
|
||||||
|
return await self.send_command("get_hashboards", message=GetHashboardsRequest())
|
||||||
|
|
||||||
|
async def get_support_archive(self) -> dict:
|
||||||
|
return await self.send_command(
|
||||||
|
"get_support_archive", message=GetSupportArchiveRequest()
|
||||||
)
|
)
|
||||||
|
|
||||||
async def enable_hashboards(
|
async def enable_hashboards(
|
||||||
self,
|
self,
|
||||||
hashboard_ids: List[str],
|
hashboard_ids: List[str],
|
||||||
save_action: SaveAction = SaveAction.SAVE_ACTION_SAVE_AND_APPLY,
|
save_action: SaveAction = SaveAction.SAVE_ACTION_SAVE_AND_APPLY,
|
||||||
):
|
) -> dict:
|
||||||
return await self.send_command(
|
return await self.send_command(
|
||||||
"enable_hashboards",
|
"enable_hashboards",
|
||||||
EnableHashboardsRequest(
|
message=EnableHashboardsRequest(
|
||||||
hashboard_ids=hashboard_ids, save_action=save_action
|
hashboard_ids=hashboard_ids, save_action=save_action
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@@ -426,10 +445,10 @@ class BOSerGRPCAPI:
|
|||||||
self,
|
self,
|
||||||
hashboard_ids: List[str],
|
hashboard_ids: List[str],
|
||||||
save_action: SaveAction = SaveAction.SAVE_ACTION_SAVE_AND_APPLY,
|
save_action: SaveAction = SaveAction.SAVE_ACTION_SAVE_AND_APPLY,
|
||||||
):
|
) -> dict:
|
||||||
return await self.send_command(
|
return await self.send_command(
|
||||||
"disable_hashboards",
|
"disable_hashboards",
|
||||||
DisableHashboardsRequest(
|
message=DisableHashboardsRequest(
|
||||||
hashboard_ids=hashboard_ids, save_action=save_action
|
hashboard_ids=hashboard_ids, save_action=save_action
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@@ -13,33 +13,38 @@
|
|||||||
# See the License for the specific language governing permissions and -
|
# See the License for the specific language governing permissions and -
|
||||||
# limitations under the License. -
|
# limitations under the License. -
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
|
|
||||||
from pyasic import settings
|
from pyasic import settings
|
||||||
from pyasic.errors import APIError
|
from pyasic.errors import APIError
|
||||||
|
from pyasic.web import BaseWebAPI
|
||||||
|
|
||||||
|
|
||||||
class BOSMinerLuCIAPI:
|
class BOSMinerWebAPI(BaseWebAPI):
|
||||||
def __init__(self, ip: str, pwd: str):
|
def __init__(self, ip: str) -> None:
|
||||||
self.ip = ip
|
super().__init__(ip)
|
||||||
self.username = "root"
|
self.username = "root"
|
||||||
self.pwd = pwd
|
self.pwd = settings.get("default_bosminer_password", "root")
|
||||||
self.port = 80
|
self.port = 80
|
||||||
|
|
||||||
async def multicommand(self, *commands: str) -> dict:
|
async def send_command(
|
||||||
data = {}
|
self,
|
||||||
for command in commands:
|
command: str | bytes,
|
||||||
data[command] = await self.send_command(command, ignore_errors=True)
|
ignore_errors: bool = False,
|
||||||
return data
|
allow_warning: bool = True,
|
||||||
|
privileged: bool = False,
|
||||||
async def send_command(self, path: str, ignore_errors: bool = False) -> dict:
|
**parameters: Any,
|
||||||
|
) -> dict:
|
||||||
try:
|
try:
|
||||||
async with httpx.AsyncClient(transport=settings.transport()) as client:
|
async with httpx.AsyncClient(transport=settings.transport()) as client:
|
||||||
await self.auth(client)
|
await self.auth(client)
|
||||||
data = await client.get(
|
data = await client.get(
|
||||||
f"http://{self.ip}:{self.port}/cgi-bin/luci/{path}",
|
f"http://{self.ip}:{self.port}/cgi-bin/luci/{command}",
|
||||||
headers={"User-Agent": "BTC Tools v0.1"},
|
headers={"User-Agent": "BTC Tools v0.1"},
|
||||||
)
|
)
|
||||||
if data.status_code == 200:
|
if data.status_code == 200:
|
||||||
@@ -47,14 +52,20 @@ class BOSMinerLuCIAPI:
|
|||||||
if ignore_errors:
|
if ignore_errors:
|
||||||
return {}
|
return {}
|
||||||
raise APIError(
|
raise APIError(
|
||||||
f"LUCI web command failed: path={path}, code={data.status_code}"
|
f"LUCI web command failed: command={command}, code={data.status_code}"
|
||||||
)
|
)
|
||||||
except (httpx.HTTPError, json.JSONDecodeError):
|
except (httpx.HTTPError, json.JSONDecodeError):
|
||||||
if ignore_errors:
|
if ignore_errors:
|
||||||
return {}
|
return {}
|
||||||
raise APIError(f"LUCI web command failed: path={path}")
|
raise APIError(f"LUCI web command failed: command={command}")
|
||||||
|
|
||||||
async def auth(self, session: httpx.AsyncClient):
|
async def multicommand(self, *commands: str) -> dict:
|
||||||
|
data = {}
|
||||||
|
for command in commands:
|
||||||
|
data[command] = await self.send_command(command, ignore_errors=True)
|
||||||
|
return data
|
||||||
|
|
||||||
|
async def auth(self, session: httpx.AsyncClient) -> None:
|
||||||
login = {"luci_username": self.username, "luci_password": self.pwd}
|
login = {"luci_username": self.username, "luci_password": self.pwd}
|
||||||
url = f"http://{self.ip}:{self.port}/cgi-bin/luci"
|
url = f"http://{self.ip}:{self.port}/cgi-bin/luci"
|
||||||
headers = {
|
headers = {
|
||||||
@@ -63,22 +74,22 @@ class BOSMinerLuCIAPI:
|
|||||||
}
|
}
|
||||||
await session.post(url, headers=headers, data=login)
|
await session.post(url, headers=headers, data=login)
|
||||||
|
|
||||||
async def get_net_conf(self):
|
async def get_net_conf(self) -> dict:
|
||||||
return await self.send_command("admin/network/iface_status/lan")
|
return await self.send_command("admin/network/iface_status/lan")
|
||||||
|
|
||||||
async def get_cfg_metadata(self):
|
async def get_cfg_metadata(self) -> dict:
|
||||||
return await self.send_command("admin/miner/cfg_metadata")
|
return await self.send_command("admin/miner/cfg_metadata")
|
||||||
|
|
||||||
async def get_cfg_data(self):
|
async def get_cfg_data(self) -> dict:
|
||||||
return await self.send_command("admin/miner/cfg_data")
|
return await self.send_command("admin/miner/cfg_data")
|
||||||
|
|
||||||
async def get_bos_info(self):
|
async def get_bos_info(self) -> dict:
|
||||||
return await self.send_command("bos/info")
|
return await self.send_command("bos/info")
|
||||||
|
|
||||||
async def get_overview(self):
|
async def get_overview(self) -> dict:
|
||||||
return await self.send_command(
|
return await self.send_command(
|
||||||
"admin/status/overview?status=1"
|
"admin/status/overview?status=1"
|
||||||
) # needs status=1 or it fails
|
) # needs status=1 or it fails
|
||||||
|
|
||||||
async def get_api_status(self):
|
async def get_api_status(self) -> dict:
|
||||||
return await self.send_command("admin/miner/api_status")
|
return await self.send_command("admin/miner/api_status")
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
# ------------------------------------------------------------------------------
|
|
||||||
# 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. -
|
|
||||||
# ------------------------------------------------------------------------------
|
|
||||||
import json
|
|
||||||
from typing import Union
|
|
||||||
|
|
||||||
import httpx
|
|
||||||
|
|
||||||
from pyasic import settings
|
|
||||||
|
|
||||||
|
|
||||||
class BOSerGraphQLAPI:
|
|
||||||
def __init__(self, ip: str, pwd: str):
|
|
||||||
self.ip = ip
|
|
||||||
self.username = "root"
|
|
||||||
self.pwd = pwd
|
|
||||||
self.port = 80
|
|
||||||
|
|
||||||
async def multicommand(self, *commands: dict) -> dict:
|
|
||||||
def merge(*d: dict):
|
|
||||||
ret = {}
|
|
||||||
for i in d:
|
|
||||||
if i:
|
|
||||||
for k in i:
|
|
||||||
if k not in ret:
|
|
||||||
ret[k] = i[k]
|
|
||||||
else:
|
|
||||||
ret[k] = merge(ret[k], i[k])
|
|
||||||
return None if ret == {} else ret
|
|
||||||
|
|
||||||
command = merge(*commands)
|
|
||||||
data = await self.send_command(command)
|
|
||||||
if data is not None:
|
|
||||||
if data.get("data") is None:
|
|
||||||
try:
|
|
||||||
commands = list(commands)
|
|
||||||
# noinspection PyTypeChecker
|
|
||||||
commands.remove({"bos": {"faultLight": None}})
|
|
||||||
command = merge(*commands)
|
|
||||||
data = await self.send_command(command)
|
|
||||||
except (LookupError, ValueError):
|
|
||||||
pass
|
|
||||||
if not data:
|
|
||||||
data = {}
|
|
||||||
data["multicommand"] = False
|
|
||||||
return data
|
|
||||||
|
|
||||||
async def send_command(
|
|
||||||
self,
|
|
||||||
command: dict,
|
|
||||||
) -> dict:
|
|
||||||
url = f"http://{self.ip}:{self.port}/graphql"
|
|
||||||
query = command
|
|
||||||
if command is None:
|
|
||||||
return {}
|
|
||||||
if command.get("query") is None:
|
|
||||||
query = {"query": self.parse_command(command)}
|
|
||||||
try:
|
|
||||||
async with httpx.AsyncClient(transport=settings.transport()) as client:
|
|
||||||
await self.auth(client)
|
|
||||||
data = await client.post(url, json=query)
|
|
||||||
except httpx.HTTPError:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
if data.status_code == 200:
|
|
||||||
try:
|
|
||||||
return data.json()
|
|
||||||
except json.decoder.JSONDecodeError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def parse_command(self, graphql_command: Union[dict, set]) -> str:
|
|
||||||
if isinstance(graphql_command, dict):
|
|
||||||
data = []
|
|
||||||
for key in graphql_command:
|
|
||||||
if graphql_command[key] is not None:
|
|
||||||
parsed = self.parse_command(graphql_command[key])
|
|
||||||
data.append(key + parsed)
|
|
||||||
else:
|
|
||||||
data.append(key)
|
|
||||||
else:
|
|
||||||
data = graphql_command
|
|
||||||
return "{" + ",".join(data) + "}"
|
|
||||||
|
|
||||||
async def auth(self, client: httpx.AsyncClient) -> None:
|
|
||||||
url = f"http://{self.ip}:{self.port}/graphql"
|
|
||||||
await client.post(
|
|
||||||
url,
|
|
||||||
json={
|
|
||||||
"query": (
|
|
||||||
f'mutation{{auth{{login(username:"{self.username}", password:"{self.pwd}"){{__typename}}}}}}'
|
|
||||||
)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
@@ -13,8 +13,10 @@
|
|||||||
# See the License for the specific language governing permissions and -
|
# See the License for the specific language governing permissions and -
|
||||||
# limitations under the License. -
|
# limitations under the License. -
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import json
|
import json
|
||||||
from typing import Union
|
from typing import Any
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
|
|
||||||
@@ -28,32 +30,30 @@ class ePICWebAPI(BaseWebAPI):
|
|||||||
super().__init__(ip)
|
super().__init__(ip)
|
||||||
self.username = "root"
|
self.username = "root"
|
||||||
self.pwd = settings.get("default_epic_web_password", "letmein")
|
self.pwd = settings.get("default_epic_web_password", "letmein")
|
||||||
self.token = None
|
|
||||||
self.port = 4028
|
self.port = 4028
|
||||||
|
self.token = None
|
||||||
|
|
||||||
async def send_command(
|
async def send_command(
|
||||||
self,
|
self,
|
||||||
command: Union[str, bytes],
|
command: str | bytes,
|
||||||
ignore_errors: bool = False,
|
ignore_errors: bool = False,
|
||||||
allow_warning: bool = True,
|
allow_warning: bool = True,
|
||||||
post: bool = False,
|
privileged: bool = False,
|
||||||
**parameters: Union[str, int, bool],
|
**parameters: Any,
|
||||||
) -> dict:
|
) -> dict:
|
||||||
if post or parameters != {}:
|
post = privileged or not parameters == {}
|
||||||
post = True
|
|
||||||
|
|
||||||
async with httpx.AsyncClient(transport=settings.transport()) as client:
|
async with httpx.AsyncClient(transport=settings.transport()) as client:
|
||||||
for i in range(settings.get("get_data_retries", 1) + 1):
|
for i in range(settings.get("get_data_retries", 1) + 1):
|
||||||
try:
|
try:
|
||||||
if post:
|
if post:
|
||||||
epic_param = {
|
|
||||||
"param": parameters.get("parameters"),
|
|
||||||
"password": self.pwd,
|
|
||||||
}
|
|
||||||
response = await client.post(
|
response = await client.post(
|
||||||
f"http://{self.ip}:{self.port}/{command}",
|
f"http://{self.ip}:{self.port}/{command}",
|
||||||
timeout=5,
|
timeout=5,
|
||||||
json=epic_param,
|
json={
|
||||||
|
**parameters,
|
||||||
|
"password": self.pwd,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
response = await client.get(
|
response = await client.get(
|
||||||
@@ -89,31 +89,31 @@ class ePICWebAPI(BaseWebAPI):
|
|||||||
return data
|
return data
|
||||||
|
|
||||||
async def restart_epic(self) -> dict:
|
async def restart_epic(self) -> dict:
|
||||||
return await self.send_command("softreboot", post=True)
|
return await self.send_command("softreboot", privileged=True)
|
||||||
|
|
||||||
async def reboot(self) -> dict:
|
async def reboot(self) -> dict:
|
||||||
return await self.send_command("reboot", post=True)
|
return await self.send_command("reboot", privileged=True)
|
||||||
|
|
||||||
async def pause_mining(self) -> dict:
|
async def pause_mining(self) -> dict:
|
||||||
return await self.send_command("miner", post=True, parameters="Stop")
|
return await self.send_command("miner", param="Stop")
|
||||||
|
|
||||||
async def resume_mining(self) -> dict:
|
async def resume_mining(self) -> dict:
|
||||||
return await self.send_command("miner", post=True, parameters="Autostart")
|
return await self.send_command("miner", param="Autostart")
|
||||||
|
|
||||||
async def stop_mining(self) -> dict:
|
async def stop_mining(self) -> dict:
|
||||||
return await self.send_command("miner", post=True, parameters="Stop")
|
return await self.send_command("miner", param="Stop")
|
||||||
|
|
||||||
async def start_mining(self) -> dict:
|
async def start_mining(self) -> dict:
|
||||||
return await self.send_command("miner", post=True, parameters="Autostart")
|
return await self.send_command("miner", param="Autostart")
|
||||||
|
|
||||||
async def summary(self):
|
async def summary(self) -> dict:
|
||||||
return await self.send_command("summary")
|
return await self.send_command("summary")
|
||||||
|
|
||||||
async def hashrate(self):
|
async def hashrate(self) -> dict:
|
||||||
return await self.send_command("hashrate")
|
return await self.send_command("hashrate")
|
||||||
|
|
||||||
async def network(self):
|
async def network(self) -> dict:
|
||||||
return await self.send_command("network")
|
return await self.send_command("network")
|
||||||
|
|
||||||
async def capabilities(self):
|
async def capabilities(self) -> dict:
|
||||||
return await self.send_command("capabilities")
|
return await self.send_command("capabilities")
|
||||||
|
|||||||
@@ -13,9 +13,11 @@
|
|||||||
# See the License for the specific language governing permissions and -
|
# See the License for the specific language governing permissions and -
|
||||||
# limitations under the License. -
|
# limitations under the License. -
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import warnings
|
import warnings
|
||||||
from typing import Union
|
from typing import Any
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
|
|
||||||
@@ -28,9 +30,9 @@ class GoldshellWebAPI(BaseWebAPI):
|
|||||||
super().__init__(ip)
|
super().__init__(ip)
|
||||||
self.username = "admin"
|
self.username = "admin"
|
||||||
self.pwd = settings.get("default_goldshell_web_password", "123456789")
|
self.pwd = settings.get("default_goldshell_web_password", "123456789")
|
||||||
self.jwt = None
|
self.token = None
|
||||||
|
|
||||||
async def auth(self):
|
async def auth(self) -> str | None:
|
||||||
async with httpx.AsyncClient(transport=settings.transport()) as client:
|
async with httpx.AsyncClient(transport=settings.transport()) as client:
|
||||||
try:
|
try:
|
||||||
await client.get(f"http://{self.ip}:{self.port}/user/logout")
|
await client.get(f"http://{self.ip}:{self.port}/user/logout")
|
||||||
@@ -54,47 +56,43 @@ class GoldshellWebAPI(BaseWebAPI):
|
|||||||
f"Could not authenticate web token with miner: {self}"
|
f"Could not authenticate web token with miner: {self}"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.jwt = auth.get("JWT Token")
|
self.token = auth.get("JWT Token")
|
||||||
else:
|
else:
|
||||||
self.jwt = auth.get("JWT Token")
|
self.token = auth.get("JWT Token")
|
||||||
return self.jwt
|
return self.token
|
||||||
|
|
||||||
async def send_command(
|
async def send_command(
|
||||||
self,
|
self,
|
||||||
command: Union[str, bytes],
|
command: str | bytes,
|
||||||
ignore_errors: bool = False,
|
ignore_errors: bool = False,
|
||||||
allow_warning: bool = True,
|
allow_warning: bool = True,
|
||||||
**parameters: Union[str, int, bool],
|
privileged: bool = False,
|
||||||
|
**parameters: Any,
|
||||||
) -> dict:
|
) -> dict:
|
||||||
if parameters.get("pool_pwd"):
|
if self.token is None:
|
||||||
parameters["pass"] = parameters["pool_pwd"]
|
|
||||||
parameters.pop("pool_pwd")
|
|
||||||
if self.jwt is None:
|
|
||||||
await self.auth()
|
await self.auth()
|
||||||
async with httpx.AsyncClient(transport=settings.transport()) as client:
|
async with httpx.AsyncClient(transport=settings.transport()) as client:
|
||||||
for _ in range(settings.get("get_data_retries", 1)):
|
for _ in range(settings.get("get_data_retries", 1)):
|
||||||
try:
|
try:
|
||||||
if parameters:
|
if not parameters == {}:
|
||||||
response = await client.put(
|
response = await client.put(
|
||||||
f"http://{self.ip}:{self.port}/mcb/{command}",
|
f"http://{self.ip}:{self.port}/mcb/{command}",
|
||||||
headers={"Authorization": "Bearer " + self.jwt},
|
headers={"Authorization": "Bearer " + self.token},
|
||||||
timeout=settings.get("api_function_timeout", 5),
|
timeout=settings.get("api_function_timeout", 5),
|
||||||
json=parameters,
|
json=parameters,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
response = await client.get(
|
response = await client.get(
|
||||||
f"http://{self.ip}:{self.port}/mcb/{command}",
|
f"http://{self.ip}:{self.port}/mcb/{command}",
|
||||||
headers={"Authorization": "Bearer " + self.jwt},
|
headers={"Authorization": "Bearer " + self.token},
|
||||||
timeout=settings.get("api_function_timeout", 5),
|
timeout=settings.get("api_function_timeout", 5),
|
||||||
)
|
)
|
||||||
json_data = response.json()
|
json_data = response.json()
|
||||||
return json_data
|
return json_data
|
||||||
except httpx.HTTPError:
|
|
||||||
pass
|
|
||||||
except json.JSONDecodeError:
|
|
||||||
pass
|
|
||||||
except TypeError:
|
except TypeError:
|
||||||
await self.auth()
|
await self.auth()
|
||||||
|
except (httpx.HTTPError, json.JSONDecodeError):
|
||||||
|
pass
|
||||||
|
|
||||||
async def multicommand(
|
async def multicommand(
|
||||||
self, *commands: str, ignore_errors: bool = False, allow_warning: bool = True
|
self, *commands: str, ignore_errors: bool = False, allow_warning: bool = True
|
||||||
@@ -107,7 +105,7 @@ class GoldshellWebAPI(BaseWebAPI):
|
|||||||
try:
|
try:
|
||||||
response = await client.get(
|
response = await client.get(
|
||||||
f"http://{self.ip}:{self.port}/mcb/{command}",
|
f"http://{self.ip}:{self.port}/mcb/{command}",
|
||||||
headers={"Authorization": "Bearer " + self.jwt},
|
headers={"Authorization": "Bearer " + self.token},
|
||||||
timeout=settings.get("api_function_timeout", 5),
|
timeout=settings.get("api_function_timeout", 5),
|
||||||
)
|
)
|
||||||
json_data = response.json()
|
json_data = response.json()
|
||||||
@@ -120,19 +118,25 @@ class GoldshellWebAPI(BaseWebAPI):
|
|||||||
await self.auth()
|
await self.auth()
|
||||||
return data
|
return data
|
||||||
|
|
||||||
async def pools(self):
|
async def pools(self) -> dict:
|
||||||
return await self.send_command("pools")
|
return await self.send_command("pools")
|
||||||
|
|
||||||
async def newpool(self, url: str, user: str, password: str):
|
async def newpool(self, url: str, user: str, password: str) -> dict:
|
||||||
return await self.send_command("newpool", url=url, user=user, pool_pwd=password)
|
# looks dumb, but cant pass `pass` since it is a built in type
|
||||||
|
|
||||||
async def delpool(self, url: str, user: str, password: str, dragid: int = 0):
|
|
||||||
return await self.send_command(
|
return await self.send_command(
|
||||||
"delpool", url=url, user=user, pool_pwd=password, dragid=dragid
|
"newpool", **{"url": url, "user": user, "pass": password}
|
||||||
)
|
)
|
||||||
|
|
||||||
async def setting(self):
|
async def delpool(
|
||||||
|
self, url: str, user: str, password: str, dragid: int = 0
|
||||||
|
) -> dict:
|
||||||
|
# looks dumb, but cant pass `pass` since it is a built in type
|
||||||
|
return await self.send_command(
|
||||||
|
"delpool", **{"url": url, "user": user, "pass": password, "dragid": dragid}
|
||||||
|
)
|
||||||
|
|
||||||
|
async def setting(self) -> dict:
|
||||||
return await self.send_command("setting")
|
return await self.send_command("setting")
|
||||||
|
|
||||||
async def status(self):
|
async def status(self) -> dict:
|
||||||
return await self.send_command("status")
|
return await self.send_command("status")
|
||||||
|
|||||||
@@ -13,9 +13,11 @@
|
|||||||
# See the License for the specific language governing permissions and -
|
# See the License for the specific language governing permissions and -
|
||||||
# limitations under the License. -
|
# limitations under the License. -
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import warnings
|
import warnings
|
||||||
from typing import Union
|
from typing import Any
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
|
|
||||||
@@ -29,9 +31,9 @@ class InnosiliconWebAPI(BaseWebAPI):
|
|||||||
super().__init__(ip)
|
super().__init__(ip)
|
||||||
self.username = "admin"
|
self.username = "admin"
|
||||||
self.pwd = settings.get("default_innosilicon_web_password", "admin")
|
self.pwd = settings.get("default_innosilicon_web_password", "admin")
|
||||||
self.jwt = None
|
self.token = None
|
||||||
|
|
||||||
async def auth(self):
|
async def auth(self) -> str | None:
|
||||||
async with httpx.AsyncClient(transport=settings.transport()) as client:
|
async with httpx.AsyncClient(transport=settings.transport()) as client:
|
||||||
try:
|
try:
|
||||||
auth = await client.post(
|
auth = await client.post(
|
||||||
@@ -42,24 +44,25 @@ class InnosiliconWebAPI(BaseWebAPI):
|
|||||||
warnings.warn(f"Could not authenticate web token with miner: {self}")
|
warnings.warn(f"Could not authenticate web token with miner: {self}")
|
||||||
else:
|
else:
|
||||||
json_auth = auth.json()
|
json_auth = auth.json()
|
||||||
self.jwt = json_auth.get("jwt")
|
self.token = json_auth.get("jwt")
|
||||||
return self.jwt
|
return self.token
|
||||||
|
|
||||||
async def send_command(
|
async def send_command(
|
||||||
self,
|
self,
|
||||||
command: Union[str, bytes],
|
command: str | bytes,
|
||||||
ignore_errors: bool = False,
|
ignore_errors: bool = False,
|
||||||
allow_warning: bool = True,
|
allow_warning: bool = True,
|
||||||
**parameters: Union[str, int, bool],
|
privileged: bool = False,
|
||||||
|
**parameters: Any,
|
||||||
) -> dict:
|
) -> dict:
|
||||||
if self.jwt is None:
|
if self.token is None:
|
||||||
await self.auth()
|
await self.auth()
|
||||||
async with httpx.AsyncClient(transport=settings.transport()) as client:
|
async with httpx.AsyncClient(transport=settings.transport()) as client:
|
||||||
for _ in range(settings.get("get_data_retries", 1)):
|
for _ in range(settings.get("get_data_retries", 1)):
|
||||||
try:
|
try:
|
||||||
response = await client.post(
|
response = await client.post(
|
||||||
f"http://{self.ip}:{self.port}/api/{command}",
|
f"http://{self.ip}:{self.port}/api/{command}",
|
||||||
headers={"Authorization": "Bearer " + self.jwt},
|
headers={"Authorization": "Bearer " + self.token},
|
||||||
timeout=settings.get("api_function_timeout", 5),
|
timeout=settings.get("api_function_timeout", 5),
|
||||||
json=parameters,
|
json=parameters,
|
||||||
)
|
)
|
||||||
@@ -79,9 +82,7 @@ class InnosiliconWebAPI(BaseWebAPI):
|
|||||||
raise APIError(json_data["message"])
|
raise APIError(json_data["message"])
|
||||||
raise APIError("Innosilicon web api command failed.")
|
raise APIError("Innosilicon web api command failed.")
|
||||||
return json_data
|
return json_data
|
||||||
except httpx.HTTPError:
|
except (httpx.HTTPError, json.JSONDecodeError):
|
||||||
pass
|
|
||||||
except json.JSONDecodeError:
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
async def multicommand(
|
async def multicommand(
|
||||||
@@ -95,7 +96,7 @@ class InnosiliconWebAPI(BaseWebAPI):
|
|||||||
try:
|
try:
|
||||||
response = await client.post(
|
response = await client.post(
|
||||||
f"http://{self.ip}:{self.port}/api/{command}",
|
f"http://{self.ip}:{self.port}/api/{command}",
|
||||||
headers={"Authorization": "Bearer " + self.jwt},
|
headers={"Authorization": "Bearer " + self.token},
|
||||||
timeout=settings.get("api_function_timeout", 5),
|
timeout=settings.get("api_function_timeout", 5),
|
||||||
)
|
)
|
||||||
json_data = response.json()
|
json_data = response.json()
|
||||||
@@ -123,14 +124,14 @@ class InnosiliconWebAPI(BaseWebAPI):
|
|||||||
async def type(self) -> dict:
|
async def type(self) -> dict:
|
||||||
return await self.send_command("type")
|
return await self.send_command("type")
|
||||||
|
|
||||||
async def get_all(self):
|
async def get_all(self) -> dict:
|
||||||
return await self.send_command("getAll")
|
return await self.send_command("getAll")
|
||||||
|
|
||||||
async def get_error_detail(self):
|
async def get_error_detail(self) -> dict:
|
||||||
return await self.send_command("getErrorDetail")
|
return await self.send_command("getErrorDetail")
|
||||||
|
|
||||||
async def pools(self):
|
async def pools(self) -> dict:
|
||||||
return await self.send_command("pools")
|
return await self.send_command("pools")
|
||||||
|
|
||||||
async def poweroff(self):
|
async def poweroff(self) -> dict:
|
||||||
return await self.send_command("poweroff")
|
return await self.send_command("poweroff")
|
||||||
|
|||||||
@@ -13,9 +13,11 @@
|
|||||||
# See the License for the specific language governing permissions and -
|
# See the License for the specific language governing permissions and -
|
||||||
# limitations under the License. -
|
# limitations under the License. -
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import warnings
|
import warnings
|
||||||
from typing import Union
|
from typing import Any
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
|
|
||||||
@@ -30,7 +32,7 @@ class VNishWebAPI(BaseWebAPI):
|
|||||||
self.pwd = settings.get("default_vnish_web_password", "admin")
|
self.pwd = settings.get("default_vnish_web_password", "admin")
|
||||||
self.token = None
|
self.token = None
|
||||||
|
|
||||||
async def auth(self):
|
async def auth(self) -> str | None:
|
||||||
async with httpx.AsyncClient(transport=settings.transport()) as client:
|
async with httpx.AsyncClient(transport=settings.transport()) as client:
|
||||||
try:
|
try:
|
||||||
auth = await client.post(
|
auth = await client.post(
|
||||||
@@ -51,11 +53,13 @@ class VNishWebAPI(BaseWebAPI):
|
|||||||
|
|
||||||
async def send_command(
|
async def send_command(
|
||||||
self,
|
self,
|
||||||
command: Union[str, bytes],
|
command: str | bytes,
|
||||||
ignore_errors: bool = False,
|
ignore_errors: bool = False,
|
||||||
allow_warning: bool = True,
|
allow_warning: bool = True,
|
||||||
**parameters: Union[str, int, bool],
|
privileged: bool = False,
|
||||||
|
**parameters: Any,
|
||||||
) -> dict:
|
) -> dict:
|
||||||
|
post = privileged or not parameters == {}
|
||||||
if self.token is None:
|
if self.token is None:
|
||||||
await self.auth()
|
await self.auth()
|
||||||
async with httpx.AsyncClient(transport=settings.transport()) as client:
|
async with httpx.AsyncClient(transport=settings.transport()) as client:
|
||||||
@@ -65,15 +69,7 @@ class VNishWebAPI(BaseWebAPI):
|
|||||||
if command.startswith("system"):
|
if command.startswith("system"):
|
||||||
auth = "Bearer " + self.token
|
auth = "Bearer " + self.token
|
||||||
|
|
||||||
if parameters.get("post"):
|
if post:
|
||||||
parameters.pop("post")
|
|
||||||
response = await client.post(
|
|
||||||
f"http://{self.ip}:{self.port}/api/v1/{command}",
|
|
||||||
headers={"Authorization": auth},
|
|
||||||
timeout=settings.get("api_function_timeout", 5),
|
|
||||||
json=parameters,
|
|
||||||
)
|
|
||||||
elif not parameters == {}:
|
|
||||||
response = await client.post(
|
response = await client.post(
|
||||||
f"http://{self.ip}:{self.port}/api/v1/{command}",
|
f"http://{self.ip}:{self.port}/api/v1/{command}",
|
||||||
headers={"Authorization": auth},
|
headers={"Authorization": auth},
|
||||||
@@ -94,11 +90,7 @@ class VNishWebAPI(BaseWebAPI):
|
|||||||
if json_data:
|
if json_data:
|
||||||
return json_data
|
return json_data
|
||||||
return {"success": True}
|
return {"success": True}
|
||||||
except httpx.HTTPError:
|
except (httpx.HTTPError, json.JSONDecodeError, AttributeError):
|
||||||
pass
|
|
||||||
except json.JSONDecodeError:
|
|
||||||
pass
|
|
||||||
except AttributeError:
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
async def multicommand(
|
async def multicommand(
|
||||||
@@ -111,40 +103,40 @@ class VNishWebAPI(BaseWebAPI):
|
|||||||
return data
|
return data
|
||||||
|
|
||||||
async def restart_vnish(self) -> dict:
|
async def restart_vnish(self) -> dict:
|
||||||
return await self.send_command("mining/restart", post=True)
|
return await self.send_command("mining/restart", privileged=True)
|
||||||
|
|
||||||
async def reboot(self) -> dict:
|
async def reboot(self) -> dict:
|
||||||
return await self.send_command("system/reboot", post=True)
|
return await self.send_command("system/reboot", privileged=True)
|
||||||
|
|
||||||
async def pause_mining(self) -> dict:
|
async def pause_mining(self) -> dict:
|
||||||
return await self.send_command("mining/pause", post=True)
|
return await self.send_command("mining/pause", privileged=True)
|
||||||
|
|
||||||
async def resume_mining(self) -> dict:
|
async def resume_mining(self) -> dict:
|
||||||
return await self.send_command("mining/resume", post=True)
|
return await self.send_command("mining/resume", privileged=True)
|
||||||
|
|
||||||
async def stop_mining(self) -> dict:
|
async def stop_mining(self) -> dict:
|
||||||
return await self.send_command("mining/stop", post=True)
|
return await self.send_command("mining/stop", privileged=True)
|
||||||
|
|
||||||
async def start_mining(self) -> dict:
|
async def start_mining(self) -> dict:
|
||||||
return await self.send_command("mining/start", post=True)
|
return await self.send_command("mining/start", privileged=True)
|
||||||
|
|
||||||
async def info(self):
|
async def info(self) -> dict:
|
||||||
return await self.send_command("info")
|
return await self.send_command("info")
|
||||||
|
|
||||||
async def summary(self):
|
async def summary(self) -> dict:
|
||||||
return await self.send_command("summary")
|
return await self.send_command("summary")
|
||||||
|
|
||||||
async def chips(self):
|
async def chips(self) -> dict:
|
||||||
return await self.send_command("chips")
|
return await self.send_command("chips")
|
||||||
|
|
||||||
async def layout(self):
|
async def layout(self) -> dict:
|
||||||
return await self.send_command("layout")
|
return await self.send_command("layout")
|
||||||
|
|
||||||
async def status(self):
|
async def status(self) -> dict:
|
||||||
return await self.send_command("status")
|
return await self.send_command("status")
|
||||||
|
|
||||||
async def settings(self):
|
async def settings(self) -> dict:
|
||||||
return await self.send_command("settings")
|
return await self.send_command("settings")
|
||||||
|
|
||||||
async def autotune_presets(self):
|
async def autotune_presets(self) -> dict:
|
||||||
return await self.send_command("autotune/presets")
|
return await self.send_command("autotune/presets")
|
||||||
|
|||||||
Reference in New Issue
Block a user