feature: optimize multicommand on new X19 models.

This commit is contained in:
UpstreamData
2023-07-24 11:34:16 -06:00
parent 2653db90e3
commit 03f2a1f9ba
8 changed files with 161 additions and 96 deletions

View File

@@ -13,7 +13,7 @@
# See the License for the specific language governing permissions and -
# limitations under the License. -
# ------------------------------------------------------------------------------
import asyncio
import logging
from pyasic.API import APIError, BaseMinerAPI
@@ -56,19 +56,19 @@ class BFGMinerAPI(BaseMinerAPI):
return data
async def _x19_multicommand(self, *commands) -> dict:
data = None
try:
data = {}
# send all commands individually
for cmd in commands:
data[cmd] = []
data[cmd].append(await self.send_command(cmd, allow_warning=True))
except APIError:
pass
except Exception as e:
logging.warning(
f"{self} - ([Hidden] X19 Multicommand) - API Command Error {e}"
tasks = []
# send all commands individually
for cmd in commands:
tasks.append(
asyncio.create_task(self._handle_multicommand(cmd, allow_warning=True))
)
all_data = await asyncio.gather(*tasks)
data = {}
for item in all_data:
data.update(item)
return data
async def version(self) -> dict:

View File

@@ -13,6 +13,7 @@
# See the License for the specific language governing permissions and -
# limitations under the License. -
# ------------------------------------------------------------------------------
import asyncio
import logging
from pyasic.API import APIError, BaseMinerAPI
@@ -57,21 +58,19 @@ class BMMinerAPI(BaseMinerAPI):
return data
async def _x19_multicommand(self, *commands, allow_warning: bool = True) -> dict:
data = None
try:
data = {}
# send all commands individually
for cmd in commands:
data[cmd] = []
data[cmd].append(
await self.send_command(cmd, allow_warning=allow_warning)
)
except APIError:
pass
except Exception as e:
logging.warning(
f"{self} - ([Hidden] X19 Multicommand) - API Command Error {e}"
tasks = []
# send all commands individually
for cmd in commands:
tasks.append(
asyncio.create_task(self._handle_multicommand(cmd, allow_warning=True))
)
all_data = await asyncio.gather(*tasks)
data = {}
for item in all_data:
data.update(item)
return data
async def version(self) -> dict:

View File

@@ -13,7 +13,7 @@
# See the License for the specific language governing permissions and -
# limitations under the License. -
# ------------------------------------------------------------------------------
import asyncio
import logging
from pyasic.API import APIError, BaseMinerAPI
@@ -56,19 +56,19 @@ class CGMinerAPI(BaseMinerAPI):
return data
async def _x19_multicommand(self, *commands) -> dict:
data = None
try:
data = {}
# send all commands individually
for cmd in commands:
data[cmd] = []
data[cmd].append(await self.send_command(cmd, allow_warning=True))
except APIError:
pass
except Exception as e:
logging.warning(
f"{self} - ([Hidden] X19 Multicommand) - API Command Error {e}"
tasks = []
# send all commands individually
for cmd in commands:
tasks.append(
asyncio.create_task(self._handle_multicommand(cmd, allow_warning=True))
)
all_data = await asyncio.gather(*tasks)
data = {}
for item in all_data:
data.update(item)
return data
async def version(self) -> dict:

View File

@@ -20,7 +20,7 @@ import logging
import time
from dataclasses import asdict, dataclass, field, fields
from datetime import datetime, timezone
from typing import List, Union, Any
from typing import Any, List, Union
from .error_codes import BraiinsOSError, InnosiliconError, WhatsminerError, X19Error
@@ -411,8 +411,12 @@ class MinerData:
field_data.append(f'error_{idx+1}="{item.error_message}"')
elif attribute == "hashboards":
for idx, item in enumerate(self[attribute]):
field_data.append(f"hashboard_{idx+1}_hashrate={item.get('hashrate', 0.0)}")
field_data.append(f"hashboard_{idx+1}_temperature={item.get('temp', 0)}")
field_data.append(
f"hashboard_{idx+1}_hashrate={item.get('hashrate', 0.0)}"
)
field_data.append(
f"hashboard_{idx+1}_temperature={item.get('temp', 0)}"
)
field_data.append(
f"hashboard_{idx+1}_chip_temperature={item.get('chip_temp', 0)}"
)

View File

@@ -26,11 +26,17 @@ from pyasic.miners.backends.cgminer import CGMiner
from pyasic.web.antminer import AntminerModernWebAPI, AntminerOldWebAPI
ANTMINER_MODERN_DATA_LOC = {
"mac": {"cmd": "get_mac", "kwargs": {}},
"mac": {
"cmd": "get_mac",
"kwargs": {"web_get_system_info": {"web": "get_system_info"}},
},
"model": {"cmd": "get_model", "kwargs": {}},
"api_ver": {"cmd": "get_api_ver", "kwargs": {"api_version": {"api": "version"}}},
"fw_ver": {"cmd": "get_fw_ver", "kwargs": {"api_version": {"api": "version"}}},
"hostname": {"cmd": "get_hostname", "kwargs": {}},
"hostname": {
"cmd": "get_hostname",
"kwargs": {"web_get_system_info": {"web": "get_system_info"}},
},
"hashrate": {"cmd": "get_hashrate", "kwargs": {"api_summary": {"api": "summary"}}},
"nominal_hashrate": {
"cmd": "get_nominal_hashrate",
@@ -42,8 +48,11 @@ ANTMINER_MODERN_DATA_LOC = {
"wattage_limit": {"cmd": "get_wattage_limit", "kwargs": {}},
"fans": {"cmd": "get_fans", "kwargs": {"api_stats": {"api": "stats"}}},
"fan_psu": {"cmd": "get_fan_psu", "kwargs": {}},
"errors": {"cmd": "get_errors", "kwargs": {}},
"fault_light": {"cmd": "get_fault_light", "kwargs": {}},
"errors": {"cmd": "get_errors", "kwargs": {"web_summary": {"web": "summary"}}},
"fault_light": {
"cmd": "get_fault_light",
"kwargs": {"web_get_blink_status": {"web": "get_blink_status"}},
},
"pools": {"cmd": "get_pools", "kwargs": {"api_pools": {"api": "pools"}}},
"is_mining": {
"cmd": "is_mining",
@@ -121,21 +130,31 @@ class AntminerModern(BMMiner):
await self.send_config(cfg)
return True
async def get_hostname(self) -> Union[str, None]:
try:
data = await self.web.get_system_info()
if data:
return data["hostname"]
except KeyError:
pass
async def get_hostname(self, web_get_system_info: dict = None) -> Union[str, None]:
if not web_get_system_info:
try:
web_get_system_info = await self.web.get_system_info()
except APIError:
pass
async def get_mac(self) -> Union[str, None]:
try:
data = await self.web.get_system_info()
if data:
return data["macaddr"]
except KeyError:
pass
if web_get_system_info:
try:
return web_get_system_info["hostname"]
except KeyError:
pass
async def get_mac(self, web_get_system_info: dict = None) -> Union[str, None]:
if not web_get_system_info:
try:
web_get_system_info = await self.web.get_system_info()
except APIError:
pass
if web_get_system_info:
try:
return web_get_system_info["macaddr"]
except KeyError:
pass
try:
data = await self.web.get_network_info()
@@ -144,12 +163,17 @@ class AntminerModern(BMMiner):
except KeyError:
pass
async def get_errors(self) -> List[MinerErrorData]:
errors = []
data = await self.web.summary()
if data:
async def get_errors(self, web_summary: dict = None) -> List[MinerErrorData]:
if not web_summary:
try:
for item in data["SUMMARY"][0]["status"]:
web_summary = await self.web.summary()
except APIError:
pass
errors = []
if web_summary:
try:
for item in web_summary["SUMMARY"][0]["status"]:
try:
if not item["status"] == "s":
errors.append(X19Error(item["msg"]))
@@ -159,15 +183,21 @@ class AntminerModern(BMMiner):
pass
return errors
async def get_fault_light(self) -> bool:
async def get_fault_light(self, web_get_blink_status: dict = None) -> bool:
if self.light:
return self.light
try:
data = await self.web.get_blink_status()
if data:
self.light = data["blink"]
except KeyError:
pass
if not web_get_blink_status:
try:
web_get_blink_status = await self.web.get_blink_status()
except APIError:
pass
if web_get_blink_status:
try:
self.light = web_get_blink_status["blink"]
except KeyError:
pass
return self.light
async def get_nominal_hashrate(self, api_stats: dict = None) -> Optional[float]:

View File

@@ -1078,7 +1078,9 @@ class BOSMiner(BaseMiner):
async def is_mining(self, api_devdetails: dict = None) -> Optional[bool]:
if not api_devdetails:
try:
api_devdetails = await self.api.send_command("devdetails", ignore_errors=True, allow_warning=False)
api_devdetails = await self.api.send_command(
"devdetails", ignore_errors=True, allow_warning=False
)
except APIError:
pass

View File

@@ -13,7 +13,7 @@
# See the License for the specific language governing permissions and -
# limitations under the License. -
# ------------------------------------------------------------------------------
import asyncio
import ipaddress
import logging
from abc import ABC, abstractmethod
@@ -430,17 +430,34 @@ class BaseMiner(ABC):
continue
if len(api_multicommand) > 0:
api_command_data = await self.api.multicommand(
*api_multicommand, allow_warning=allow_warning
api_command_task = asyncio.create_task(
self.api.multicommand(*api_multicommand, allow_warning=allow_warning)
)
else:
api_command_data = {}
api_command_task = asyncio.sleep(0)
if len(web_multicommand) > 0:
web_command_data = await self.web.multicommand(
*web_multicommand, allow_warning=allow_warning
web_command_task = asyncio.create_task(
self.web.multicommand(*web_multicommand, allow_warning=allow_warning)
)
else:
web_command_task = asyncio.sleep(0)
import pprint
from datetime import datetime
s1 = datetime.now()
web_command_data = await web_command_task
if web_command_data is None:
web_command_data = {}
print("WEB", datetime.now() - s1)
# pprint.pprint(web_command_data)
s2 = datetime.now()
api_command_data = await api_command_task
if api_command_data is None:
api_command_data = {}
print("API:", datetime.now() - s2)
# pprint.pprint(api_command_data)
miner_data = {}

View File

@@ -13,6 +13,7 @@
# See the License for the specific language governing permissions and -
# limitations under the License. -
# ------------------------------------------------------------------------------
import asyncio
import json
from typing import Union
@@ -56,25 +57,37 @@ class AntminerModernWebAPI(BaseWebAPI):
async def multicommand(
self, *commands: str, ignore_errors: bool = False, allow_warning: bool = True
) -> dict:
data = {k: None for k in commands}
data["multicommand"] = True
auth = httpx.DigestAuth(self.username, self.pwd)
async with httpx.AsyncClient() as client:
for command in commands:
try:
url = f"http://{self.ip}/cgi-bin/{command}.cgi"
ret = await client.get(url, auth=auth)
except httpx.HTTPError:
pass
else:
if ret.status_code == 200:
try:
json_data = ret.json()
data[command] = json_data
except json.decoder.JSONDecodeError:
pass
tasks = [
asyncio.create_task(self._handle_multicommand(client, command))
for command in commands
]
all_data = await asyncio.gather(*tasks)
data = {}
for item in all_data:
data.update(item)
data["multicommand"] = True
return data
async def _handle_multicommand(self, client: httpx.AsyncClient, command: str):
auth = httpx.DigestAuth(self.username, self.pwd)
try:
url = f"http://{self.ip}/cgi-bin/{command}.cgi"
ret = await client.get(url, auth=auth)
except httpx.HTTPError:
pass
else:
if ret.status_code == 200:
try:
json_data = ret.json()
return {command: json_data}
except json.decoder.JSONDecodeError:
pass
return {command: {}}
async def get_miner_conf(self) -> dict:
return await self.send_command("get_miner_conf")