feature: add basic iceriver framework.

This commit is contained in:
Upstream Data
2024-08-20 09:45:31 -06:00
parent e7ed39fe39
commit 343b5a1c50
16 changed files with 145 additions and 0 deletions

View File

@@ -339,6 +339,13 @@ class BitAxeModels(str, Enum):
return self.value
class IceRiverModels(str, Enum):
KS2 = "KS2"
def __str__(self):
return self.value
class MinerModel:
ANTMINER = AntminerModels
WHATSMINER = WhatsminerModels
@@ -348,3 +355,4 @@ class MinerModel:
AURADINE = AuradineModels
EPIC = ePICModels
BITAXE = BitAxeModels
ICERIVER = IceRiverModels

View File

@@ -24,6 +24,7 @@ from .cgminer import CGMiner
from .epic import ePIC
from .goldshell import GoldshellMiner
from .hiveon import Hiveon
from .iceriver import IceRiver
from .innosilicon import Innosilicon
from .luxminer import LUXMiner
from .marathon import MaraMiner

View File

@@ -0,0 +1,14 @@
from pyasic.miners.data import DataLocations
from pyasic.miners.device.firmware import StockFirmware
from pyasic.web.iceriver import IceRiverWebAPI
ICERIVER_DATA_LOC = DataLocations()
class IceRiver(StockFirmware):
"""Handler for IceRiver miners"""
_web_cls = IceRiverWebAPI
web: IceRiverWebAPI
data_locations = ICERIVER_DATA_LOC

View File

@@ -48,3 +48,7 @@ class ePICMake(BaseMiner):
class BitAxeMake(BaseMiner):
make = MinerMake.BITAXE
class IceRiverMake(BaseMiner):
make = MinerMake.BITAXE

View File

@@ -19,5 +19,6 @@ from .auradine import *
from .avalonminer import *
from .epic import *
from .goldshell import *
from .iceriver import *
from .innosilicon import *
from .whatsminer import *

View File

@@ -0,0 +1,23 @@
# ------------------------------------------------------------------------------
# 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 pyasic.device.models import MinerModel
from pyasic.miners.device.makes import IceRiverMake
class KS2(IceRiverMake):
raw_model = MinerModel.ICERIVER.KS2
expected_fans = 4

View File

@@ -0,0 +1 @@
from .KS2 import KS2

View File

@@ -0,0 +1 @@
from .KSX import *

View File

@@ -38,6 +38,7 @@ from pyasic.miners.bitaxe import *
from pyasic.miners.blockminer import *
from pyasic.miners.device.makes import *
from pyasic.miners.goldshell import *
from pyasic.miners.iceriver import *
from pyasic.miners.innosilicon import *
from pyasic.miners.whatsminer import *
@@ -56,6 +57,7 @@ class MinerTypes(enum.Enum):
AURADINE = 10
MARATHON = 11
BITAXE = 12
ICERIVER = 13
MINER_CLASSES = {
@@ -451,6 +453,10 @@ MINER_CLASSES = {
"BM1366": BitAxeUltra,
"BM1397": BitAxeMax,
},
MinerTypes.ICERIVER: {
None: type("IceRiverUnknown", (IceRiver, IceRiverMake), {}),
"KS2": IceRiverKS2,
},
}
@@ -623,6 +629,8 @@ class MinerFactory:
return MinerTypes.INNOSILICON
if "Miner UI" in web_text:
return MinerTypes.AURADINE
if "<TITLE>用户界面</TITLE>" in web_text:
return MinerTypes.ICERIVER
async def _get_miner_socket(self, ip: str) -> MinerTypes | None:
commands = ["version", "devdetails"]

View File

@@ -0,0 +1 @@
from .iceminer import *

View File

@@ -0,0 +1,6 @@
from pyasic.miners.backends.iceriver import IceRiver
from pyasic.miners.device.models import KS2
class IceRiverKS2(IceRiver, KS2):
pass

View File

@@ -0,0 +1 @@
from .KS2 import IceRiverKS2

View File

@@ -0,0 +1 @@
from .KSX import *

View File

@@ -39,6 +39,7 @@ _settings = { # defaults
"default_auradine_web_password": "admin",
"default_epic_web_password": "letmein",
"default_hive_web_password": "admin",
"default_iceriver_web_password": "12345678",
"default_antminer_ssh_password": "miner",
"default_bosminer_ssh_password": "root",
"socket_linger_time": 1000,

View File

@@ -19,5 +19,6 @@ from .base import BaseWebAPI
from .braiins_os import BOSerWebAPI, BOSMinerWebAPI
from .epic import ePICWebAPI
from .goldshell import GoldshellWebAPI
from .iceriver import IceRiverWebAPI
from .innosilicon import InnosiliconWebAPI
from .vnish import VNishWebAPI

73
pyasic/web/iceriver.py Normal file
View File

@@ -0,0 +1,73 @@
# ------------------------------------------------------------------------------
# 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 IceRiverWebAPI(BaseWebAPI):
def __init__(self, ip: str) -> None:
super().__init__(ip)
self.username = "admin"
self.pwd = settings.get("default_iceriver_web_password", "12345678")
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}/user/loginpost",
params={"post": "6", "user": self.username, "pwd": 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}/user/{command}", params=parameters
)
return resp.json()
except httpx.HTTPError:
raise APIError(f"Command failed: {command}")
async def locate(self, enable: bool):
return await self.send_command(
"userpanel", post="5", locate="1" if enable else "0"
)
async def userpanel(self):
return await self.send_command("userpanel", post="4")