Skip to content

Commit 2d42402

Browse files
committed
feature: add MAC address to mskminer
1 parent bf4903c commit 2d42402

File tree

4 files changed

+112
-1
lines changed

4 files changed

+112
-1
lines changed

pyasic/miners/backends/mskminer.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,14 @@
33
from pyasic import APIError
44
from pyasic.device.algorithm import AlgoHashRate
55
from pyasic.miners.backends import BMMiner
6-
from pyasic.miners.data import DataFunction, DataLocations, DataOptions, RPCAPICommand
6+
from pyasic.miners.data import (
7+
DataFunction,
8+
DataLocations,
9+
DataOptions,
10+
RPCAPICommand,
11+
WebAPICommand,
12+
)
13+
from pyasic.web.mskminer import MSKMinerWebAPI
714

815
MSKMINER_DATA_LOC = DataLocations(
916
**{
@@ -15,6 +22,10 @@
1522
"_get_fw_ver",
1623
[RPCAPICommand("rpc_version", "version")],
1724
),
25+
str(DataOptions.MAC): DataFunction(
26+
"_get_mac",
27+
[WebAPICommand("web_info_v1", "info_v1")],
28+
),
1829
str(DataOptions.HASHRATE): DataFunction(
1930
"_get_hashrate",
2031
[RPCAPICommand("rpc_stats", "stats")],
@@ -52,6 +63,9 @@ class MSKMiner(BMMiner):
5263

5364
data_locations = MSKMINER_DATA_LOC
5465

66+
web: MSKMinerWebAPI
67+
_web_cls = MSKMinerWebAPI
68+
5569
async def _get_hashrate(self, rpc_stats: dict = None) -> Optional[AlgoHashRate]:
5670
# get hr from API
5771
if rpc_stats is None:
@@ -81,3 +95,16 @@ async def _get_wattage(self, rpc_stats: dict = None) -> Optional[int]:
8195
return rpc_stats["STATS"][0]["total_power"]
8296
except (LookupError, ValueError, TypeError):
8397
pass
98+
99+
async def _get_mac(self, web_info_v1: dict = None) -> Optional[str]:
100+
if web_info_v1 is None:
101+
try:
102+
web_info_v1 = await self.web.info_v1()
103+
except APIError:
104+
pass
105+
106+
if web_info_v1 is not None:
107+
try:
108+
return web_info_v1["network_info"]["result"]["macaddr"].upper()
109+
except (LookupError, ValueError, TypeError):
110+
pass

pyasic/settings/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
"default_hive_web_password": "root",
4242
"default_iceriver_web_password": "12345678",
4343
"default_elphapex_web_password": "root",
44+
"default_mskminer_web_password": "root",
4445
"default_antminer_ssh_password": "miner",
4546
"default_bosminer_ssh_password": "root",
4647
}

pyasic/web/mskminer.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# ------------------------------------------------------------------------------
2+
# Copyright 2024 Upstream Data Inc -
3+
# -
4+
# Licensed under the Apache License, Version 2.0 (the "License"); -
5+
# you may not use this file except in compliance with the License. -
6+
# You may obtain a copy of the License at -
7+
# -
8+
# http://www.apache.org/licenses/LICENSE-2.0 -
9+
# -
10+
# Unless required by applicable law or agreed to in writing, software -
11+
# distributed under the License is distributed on an "AS IS" BASIS, -
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -
13+
# See the License for the specific language governing permissions and -
14+
# limitations under the License. -
15+
# ------------------------------------------------------------------------------
16+
from __future__ import annotations
17+
18+
import asyncio
19+
import warnings
20+
from typing import Any
21+
22+
import httpx
23+
24+
from pyasic import settings
25+
from pyasic.errors import APIError
26+
from pyasic.web.base import BaseWebAPI
27+
28+
29+
class MSKMinerWebAPI(BaseWebAPI):
30+
def __init__(self, ip: str) -> None:
31+
super().__init__(ip)
32+
self.username = "admin"
33+
self.pwd = settings.get("default_mskminer_web_password", "root")
34+
35+
async def multicommand(
36+
self, *commands: str, ignore_errors: bool = False, allow_warning: bool = True
37+
) -> dict:
38+
tasks = {c: asyncio.create_task(getattr(self, c)()) for c in commands}
39+
await asyncio.gather(*[t for t in tasks.values()])
40+
return {t: tasks[t].result() for t in tasks}
41+
42+
async def send_command(
43+
self,
44+
command: str | bytes,
45+
ignore_errors: bool = False,
46+
allow_warning: bool = True,
47+
privileged: bool = False,
48+
**parameters: Any,
49+
) -> dict:
50+
async with httpx.AsyncClient(transport=settings.transport()) as client:
51+
try:
52+
# auth
53+
await client.post(
54+
f"http://{self.ip}:{self.port}/admin/login",
55+
data={"username": self.username, "password": self.pwd},
56+
)
57+
except httpx.HTTPError:
58+
warnings.warn(f"Could not authenticate with miner web: {self}")
59+
try:
60+
resp = await client.post(
61+
f"http://{self.ip}:{self.port}/api/{command}", params=parameters
62+
)
63+
if not resp.status_code == 200:
64+
if not ignore_errors:
65+
raise APIError(f"Command failed: {command}")
66+
warnings.warn(f"Command failed: {command}")
67+
return resp.json()
68+
except httpx.HTTPError:
69+
raise APIError(f"Command failed: {command}")
70+
71+
async def info_v1(self):
72+
return await self.send_command("info_v1")

tests/miners_tests/backends_tests/mskminer_tests/version_2_6_0_39.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,16 @@
2929

3030
data = {
3131
MSKMinerS19NoPIC: {
32+
"web_info_v1": {
33+
# needs updates with real data
34+
"network_info": {
35+
"result": {
36+
"address": "192.168.1.10",
37+
"macaddr": "12:34:56:78:90:12",
38+
"netmask": "255.255.255.0",
39+
}
40+
}
41+
},
3242
"rpc_version": {
3343
"STATUS": [
3444
{
@@ -479,6 +489,7 @@ async def test_all_data_gathering(self, mock_send_bytes):
479489
if gathered_data[item] is not None:
480490
setattr(result, item, gathered_data[item])
481491

492+
self.assertEqual(result.mac, "12:34:56:78:90:12")
482493
self.assertEqual(result.api_ver, "3.1")
483494
self.assertEqual(result.fw_ver, "10 Dec 2024 14:34:31 GMT")
484495
self.assertEqual(round(result.hashrate.into(SHA256Unit.TH)), 100)

0 commit comments

Comments
 (0)