feature: add MAC address to mskminer

This commit is contained in:
Upstream Data
2025-02-11 15:47:37 -07:00
parent bf4903ce4b
commit 2d424025e9
4 changed files with 112 additions and 1 deletions

View File

@@ -3,7 +3,14 @@ from typing import Optional
from pyasic import APIError from pyasic import APIError
from pyasic.device.algorithm import AlgoHashRate from pyasic.device.algorithm import AlgoHashRate
from pyasic.miners.backends import BMMiner from pyasic.miners.backends import BMMiner
from pyasic.miners.data import DataFunction, DataLocations, DataOptions, RPCAPICommand from pyasic.miners.data import (
DataFunction,
DataLocations,
DataOptions,
RPCAPICommand,
WebAPICommand,
)
from pyasic.web.mskminer import MSKMinerWebAPI
MSKMINER_DATA_LOC = DataLocations( MSKMINER_DATA_LOC = DataLocations(
**{ **{
@@ -15,6 +22,10 @@ MSKMINER_DATA_LOC = DataLocations(
"_get_fw_ver", "_get_fw_ver",
[RPCAPICommand("rpc_version", "version")], [RPCAPICommand("rpc_version", "version")],
), ),
str(DataOptions.MAC): DataFunction(
"_get_mac",
[WebAPICommand("web_info_v1", "info_v1")],
),
str(DataOptions.HASHRATE): DataFunction( str(DataOptions.HASHRATE): DataFunction(
"_get_hashrate", "_get_hashrate",
[RPCAPICommand("rpc_stats", "stats")], [RPCAPICommand("rpc_stats", "stats")],
@@ -52,6 +63,9 @@ class MSKMiner(BMMiner):
data_locations = MSKMINER_DATA_LOC data_locations = MSKMINER_DATA_LOC
web: MSKMinerWebAPI
_web_cls = MSKMinerWebAPI
async def _get_hashrate(self, rpc_stats: dict = None) -> Optional[AlgoHashRate]: async def _get_hashrate(self, rpc_stats: dict = None) -> Optional[AlgoHashRate]:
# get hr from API # get hr from API
if rpc_stats is None: if rpc_stats is None:
@@ -81,3 +95,16 @@ class MSKMiner(BMMiner):
return rpc_stats["STATS"][0]["total_power"] return rpc_stats["STATS"][0]["total_power"]
except (LookupError, ValueError, TypeError): except (LookupError, ValueError, TypeError):
pass pass
async def _get_mac(self, web_info_v1: dict = None) -> Optional[str]:
if web_info_v1 is None:
try:
web_info_v1 = await self.web.info_v1()
except APIError:
pass
if web_info_v1 is not None:
try:
return web_info_v1["network_info"]["result"]["macaddr"].upper()
except (LookupError, ValueError, TypeError):
pass

View File

@@ -41,6 +41,7 @@ _settings = { # defaults
"default_hive_web_password": "root", "default_hive_web_password": "root",
"default_iceriver_web_password": "12345678", "default_iceriver_web_password": "12345678",
"default_elphapex_web_password": "root", "default_elphapex_web_password": "root",
"default_mskminer_web_password": "root",
"default_antminer_ssh_password": "miner", "default_antminer_ssh_password": "miner",
"default_bosminer_ssh_password": "root", "default_bosminer_ssh_password": "root",
} }

72
pyasic/web/mskminer.py Normal file
View File

@@ -0,0 +1,72 @@
# ------------------------------------------------------------------------------
# Copyright 2024 Upstream Data Inc -
# -
# Licensed under the Apache License, Version 2.0 (the "License"); -
# you may not use this file except in compliance with the License. -
# You may obtain a copy of the License at -
# -
# http://www.apache.org/licenses/LICENSE-2.0 -
# -
# Unless required by applicable law or agreed to in writing, software -
# distributed under the License is distributed on an "AS IS" BASIS, -
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -
# See the License for the specific language governing permissions and -
# limitations under the License. -
# ------------------------------------------------------------------------------
from __future__ import annotations
import asyncio
import warnings
from typing import Any
import httpx
from pyasic import settings
from pyasic.errors import APIError
from pyasic.web.base import BaseWebAPI
class MSKMinerWebAPI(BaseWebAPI):
def __init__(self, ip: str) -> None:
super().__init__(ip)
self.username = "admin"
self.pwd = settings.get("default_mskminer_web_password", "root")
async def multicommand(
self, *commands: str, ignore_errors: bool = False, allow_warning: bool = True
) -> dict:
tasks = {c: asyncio.create_task(getattr(self, c)()) for c in commands}
await asyncio.gather(*[t for t in tasks.values()])
return {t: tasks[t].result() for t in tasks}
async def send_command(
self,
command: str | bytes,
ignore_errors: bool = False,
allow_warning: bool = True,
privileged: bool = False,
**parameters: Any,
) -> dict:
async with httpx.AsyncClient(transport=settings.transport()) as client:
try:
# auth
await client.post(
f"http://{self.ip}:{self.port}/admin/login",
data={"username": self.username, "password": self.pwd},
)
except httpx.HTTPError:
warnings.warn(f"Could not authenticate with miner web: {self}")
try:
resp = await client.post(
f"http://{self.ip}:{self.port}/api/{command}", params=parameters
)
if not resp.status_code == 200:
if not ignore_errors:
raise APIError(f"Command failed: {command}")
warnings.warn(f"Command failed: {command}")
return resp.json()
except httpx.HTTPError:
raise APIError(f"Command failed: {command}")
async def info_v1(self):
return await self.send_command("info_v1")

View File

@@ -29,6 +29,16 @@ POOLS = [
data = { data = {
MSKMinerS19NoPIC: { MSKMinerS19NoPIC: {
"web_info_v1": {
# needs updates with real data
"network_info": {
"result": {
"address": "192.168.1.10",
"macaddr": "12:34:56:78:90:12",
"netmask": "255.255.255.0",
}
}
},
"rpc_version": { "rpc_version": {
"STATUS": [ "STATUS": [
{ {
@@ -479,6 +489,7 @@ class TestMSKMiners(unittest.IsolatedAsyncioTestCase):
if gathered_data[item] is not None: if gathered_data[item] is not None:
setattr(result, item, gathered_data[item]) setattr(result, item, gathered_data[item])
self.assertEqual(result.mac, "12:34:56:78:90:12")
self.assertEqual(result.api_ver, "3.1") self.assertEqual(result.api_ver, "3.1")
self.assertEqual(result.fw_ver, "10 Dec 2024 14:34:31 GMT") self.assertEqual(result.fw_ver, "10 Dec 2024 14:34:31 GMT")
self.assertEqual(round(result.hashrate.into(SHA256Unit.TH)), 100) self.assertEqual(round(result.hashrate.into(SHA256Unit.TH)), 100)