412 lines
16 KiB
Python
412 lines
16 KiB
Python
# ------------------------------------------------------------------------------
|
|
# 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. -
|
|
# ------------------------------------------------------------------------------
|
|
|
|
from typing import Any
|
|
|
|
from pydantic import BaseModel, Field
|
|
|
|
from pyasic.config.fans import (
|
|
FanModeConfig,
|
|
FanModeImmersion,
|
|
FanModeManual,
|
|
FanModeNormal,
|
|
)
|
|
from pyasic.config.mining import (
|
|
MiningModeConfig,
|
|
MiningModeHashrateTune,
|
|
MiningModeHPM,
|
|
MiningModeLPM,
|
|
MiningModeManual,
|
|
MiningModeNormal,
|
|
MiningModePowerTune,
|
|
MiningModePreset,
|
|
MiningModeSleep,
|
|
)
|
|
|
|
# Type aliases for config field types
|
|
FanModeType = FanModeNormal | FanModeManual | FanModeImmersion | FanModeConfig
|
|
MiningModeType = (
|
|
MiningModeNormal
|
|
| MiningModeHPM
|
|
| MiningModeLPM
|
|
| MiningModeSleep
|
|
| MiningModeManual
|
|
| MiningModePowerTune
|
|
| MiningModeHashrateTune
|
|
| MiningModePreset
|
|
| MiningModeConfig
|
|
)
|
|
from pyasic.config.mining.scaling import ScalingConfig
|
|
from pyasic.config.pools import PoolConfig
|
|
from pyasic.config.temperature import TemperatureConfig
|
|
from pyasic.misc import merge_dicts
|
|
|
|
|
|
class MinerConfig(BaseModel):
|
|
"""Represents the configuration for a miner including pool configuration,
|
|
fan mode, temperature settings, mining mode, and power scaling."""
|
|
|
|
class Config:
|
|
arbitrary_types_allowed = True
|
|
|
|
pools: PoolConfig = Field(default_factory=PoolConfig.default)
|
|
fan_mode: FanModeType = Field(default_factory=FanModeConfig.default)
|
|
temperature: TemperatureConfig = Field(default_factory=TemperatureConfig.default)
|
|
mining_mode: MiningModeType = Field(default_factory=MiningModeConfig.default)
|
|
|
|
def __getitem__(self, item: str) -> Any:
|
|
try:
|
|
return getattr(self, item)
|
|
except AttributeError:
|
|
raise KeyError
|
|
|
|
def as_dict(self) -> dict:
|
|
"""Converts the MinerConfig object to a dictionary."""
|
|
return self.model_dump()
|
|
|
|
def as_am_modern(self, user_suffix: str | None = None) -> dict:
|
|
"""Generates the configuration in the format suitable for modern Antminers."""
|
|
return {
|
|
**self.fan_mode.as_am_modern(),
|
|
"freq-level": "100",
|
|
**self.mining_mode.as_am_modern(),
|
|
**self.pools.as_am_modern(user_suffix=user_suffix),
|
|
**self.temperature.as_am_modern(),
|
|
}
|
|
|
|
def as_hiveon_modern(self, user_suffix: str | None = None) -> dict:
|
|
"""Generates the configuration in the format suitable for modern Hiveon."""
|
|
return {
|
|
**self.fan_mode.as_hiveon_modern(),
|
|
"freq-level": "100",
|
|
**self.mining_mode.as_hiveon_modern(),
|
|
**self.pools.as_hiveon_modern(user_suffix=user_suffix),
|
|
**self.temperature.as_hiveon_modern(),
|
|
}
|
|
|
|
def as_elphapex(self, user_suffix: str | None = None) -> dict:
|
|
"""Generates the configuration in the format suitable for modern Elphapex."""
|
|
return {
|
|
**self.fan_mode.as_elphapex(),
|
|
"fc-freq-level": "100",
|
|
**self.mining_mode.as_elphapex(),
|
|
**self.pools.as_elphapex(user_suffix=user_suffix),
|
|
**self.temperature.as_elphapex(),
|
|
}
|
|
|
|
def as_wm(self, user_suffix: str | None = None) -> dict:
|
|
"""Generates the configuration in the format suitable for Whatsminers."""
|
|
return {
|
|
**self.fan_mode.as_wm(),
|
|
**self.mining_mode.as_wm(),
|
|
**self.pools.as_wm(user_suffix=user_suffix),
|
|
**self.temperature.as_wm(),
|
|
}
|
|
|
|
def as_btminer_v3(self, user_suffix: str | None = None) -> dict:
|
|
"""Generates the configuration in the format suitable for Whatsminers running BTMiner V3."""
|
|
return {
|
|
"set.miner.pools": self.pools.as_btminer_v3(),
|
|
**self.mining_mode.as_btminer_v3(),
|
|
}
|
|
|
|
def as_am_old(self, user_suffix: str | None = None) -> dict:
|
|
"""Generates the configuration in the format suitable for old versions of Antminers."""
|
|
return {
|
|
**self.fan_mode.as_am_old(),
|
|
**self.mining_mode.as_am_old(),
|
|
**self.pools.as_am_old(user_suffix=user_suffix),
|
|
**self.temperature.as_am_old(),
|
|
}
|
|
|
|
def as_goldshell(self, user_suffix: str | None = None) -> dict:
|
|
"""Generates the configuration in the format suitable for Goldshell miners."""
|
|
return {
|
|
**self.fan_mode.as_goldshell(),
|
|
**self.mining_mode.as_goldshell(),
|
|
**self.pools.as_goldshell(user_suffix=user_suffix),
|
|
**self.temperature.as_goldshell(),
|
|
}
|
|
|
|
def as_avalon(self, user_suffix: str | None = None) -> dict:
|
|
"""Generates the configuration in the format suitable for Avalonminers."""
|
|
return {
|
|
**self.fan_mode.as_avalon(),
|
|
**self.mining_mode.as_avalon(),
|
|
**self.pools.as_avalon(user_suffix=user_suffix),
|
|
**self.temperature.as_avalon(),
|
|
}
|
|
|
|
def as_inno(self, user_suffix: str | None = None) -> dict:
|
|
"""Generates the configuration in the format suitable for Innosilicon miners."""
|
|
return {
|
|
**self.fan_mode.as_inno(),
|
|
**self.mining_mode.as_inno(),
|
|
**self.pools.as_inno(user_suffix=user_suffix),
|
|
**self.temperature.as_inno(),
|
|
}
|
|
|
|
def as_bosminer(self, user_suffix: str | None = None) -> dict:
|
|
"""Generates the configuration in the bosminer.toml format."""
|
|
return {
|
|
**merge_dicts(self.fan_mode.as_bosminer(), self.temperature.as_bosminer()),
|
|
**self.mining_mode.as_bosminer(),
|
|
**self.pools.as_bosminer(user_suffix=user_suffix),
|
|
}
|
|
|
|
def as_boser(self, user_suffix: str | None = None) -> dict:
|
|
"""Generates the configuration in the format suitable for BOSer."""
|
|
return {
|
|
**self.fan_mode.as_boser(),
|
|
**self.temperature.as_boser(),
|
|
**self.mining_mode.as_boser(),
|
|
**self.pools.as_boser(user_suffix=user_suffix),
|
|
}
|
|
|
|
def as_epic(self, user_suffix: str | None = None) -> dict:
|
|
"""Generates the configuration in the format suitable for ePIC miners."""
|
|
return {
|
|
**merge_dicts(self.fan_mode.as_epic(), self.temperature.as_epic()),
|
|
**self.mining_mode.as_epic(),
|
|
**self.pools.as_epic(user_suffix=user_suffix),
|
|
}
|
|
|
|
def as_auradine(self, user_suffix: str | None = None) -> dict:
|
|
"""Generates the configuration in the format suitable for Auradine miners."""
|
|
return {
|
|
**self.fan_mode.as_auradine(),
|
|
**self.temperature.as_auradine(),
|
|
**self.mining_mode.as_auradine(),
|
|
**self.pools.as_auradine(user_suffix=user_suffix),
|
|
}
|
|
|
|
def as_mara(self, user_suffix: str | None = None) -> dict:
|
|
return {
|
|
**self.fan_mode.as_mara(),
|
|
**self.temperature.as_mara(),
|
|
**self.mining_mode.as_mara(),
|
|
**self.pools.as_mara(user_suffix=user_suffix),
|
|
}
|
|
|
|
def as_espminer(self, user_suffix: str | None = None) -> dict:
|
|
return {
|
|
**self.fan_mode.as_espminer(),
|
|
**self.temperature.as_espminer(),
|
|
**self.mining_mode.as_espminer(),
|
|
**self.pools.as_espminer(user_suffix=user_suffix),
|
|
}
|
|
|
|
def as_luxos(self, user_suffix: str | None = None) -> dict:
|
|
return {
|
|
**self.fan_mode.as_luxos(),
|
|
**self.temperature.as_luxos(),
|
|
**self.mining_mode.as_luxos(),
|
|
**self.pools.as_luxos(user_suffix=user_suffix),
|
|
}
|
|
|
|
def as_vnish(self, user_suffix: str | None = None) -> dict:
|
|
main_cfg = {
|
|
"miner": {
|
|
**self.fan_mode.as_vnish(),
|
|
**self.temperature.as_vnish(),
|
|
**self.mining_mode.as_vnish(),
|
|
**self.pools.as_vnish(user_suffix=user_suffix),
|
|
}
|
|
}
|
|
if isinstance(self.fan_mode, FanModeNormal):
|
|
main_cfg["miner"]["cooling"]["mode"]["param"] = self.temperature.target
|
|
return main_cfg
|
|
|
|
def as_hammer(self, *args, **kwargs) -> dict:
|
|
return self.as_am_modern(*args, **kwargs)
|
|
|
|
@classmethod
|
|
def from_dict(cls, dict_conf: dict) -> "MinerConfig":
|
|
"""Constructs a MinerConfig object from a dictionary."""
|
|
return cls(
|
|
pools=PoolConfig.from_dict(dict_conf.get("pools")),
|
|
mining_mode=MiningModeConfig.from_dict(dict_conf.get("mining_mode")),
|
|
fan_mode=FanModeConfig.from_dict(dict_conf.get("fan_mode")),
|
|
temperature=TemperatureConfig.from_dict(dict_conf.get("temperature")),
|
|
)
|
|
|
|
@classmethod
|
|
def from_api(cls, api_pools: dict) -> "MinerConfig":
|
|
"""Constructs a MinerConfig object from API pool data."""
|
|
return cls(pools=PoolConfig.from_api(api_pools))
|
|
|
|
@classmethod
|
|
def from_am_modern(cls, web_conf: dict) -> "MinerConfig":
|
|
"""Constructs a MinerConfig object from web configuration for modern Antminers."""
|
|
return cls(
|
|
pools=PoolConfig.from_am_modern(web_conf),
|
|
mining_mode=MiningModeConfig.from_am_modern(web_conf),
|
|
fan_mode=FanModeConfig.from_am_modern(web_conf),
|
|
)
|
|
|
|
@classmethod
|
|
def from_hiveon_modern(cls, web_conf: dict) -> "MinerConfig":
|
|
"""Constructs a MinerConfig object from web configuration for Hiveon."""
|
|
return cls(
|
|
pools=PoolConfig.from_hiveon_modern(web_conf),
|
|
mining_mode=MiningModeConfig.from_hiveon_modern(web_conf),
|
|
fan_mode=FanModeConfig.from_hiveon_modern(web_conf),
|
|
)
|
|
|
|
@classmethod
|
|
def from_elphapex(cls, web_conf: dict) -> "MinerConfig":
|
|
"""Constructs a MinerConfig object from web configuration for modern Antminers."""
|
|
return cls(
|
|
pools=PoolConfig.from_elphapex(web_conf),
|
|
mining_mode=MiningModeConfig.from_elphapex(web_conf),
|
|
fan_mode=FanModeConfig.from_elphapex(web_conf),
|
|
)
|
|
|
|
@classmethod
|
|
def from_am_old(cls, web_conf: dict) -> "MinerConfig":
|
|
"""Constructs a MinerConfig object from web configuration for old versions of Antminers."""
|
|
return cls.from_am_modern(web_conf)
|
|
|
|
@classmethod
|
|
def from_goldshell(cls, web_conf: dict) -> "MinerConfig":
|
|
"""Constructs a MinerConfig object from web configuration for Goldshell miners."""
|
|
return cls(pools=PoolConfig.from_am_modern(web_conf))
|
|
|
|
@classmethod
|
|
def from_goldshell_list(cls, web_conf: list) -> "MinerConfig":
|
|
"""Constructs a MinerConfig object from web configuration for Goldshell miners."""
|
|
return cls(pools=PoolConfig.from_goldshell(web_conf))
|
|
|
|
@classmethod
|
|
def from_goldshell_byte(cls, web_conf: list) -> "MinerConfig":
|
|
"""Constructs a MinerConfig object from web configuration for Goldshell Byte miners."""
|
|
return cls(pools=PoolConfig.from_goldshell_byte(web_conf))
|
|
|
|
@classmethod
|
|
def from_inno(cls, web_pools: list) -> "MinerConfig":
|
|
"""Constructs a MinerConfig object from web configuration for Innosilicon miners."""
|
|
return cls(pools=PoolConfig.from_inno(web_pools))
|
|
|
|
@classmethod
|
|
def from_bosminer(cls, toml_conf: dict) -> "MinerConfig":
|
|
"""Constructs a MinerConfig object from the bosminer.toml file, same as the `as_bosminer` dumps a dict for writing to that file as toml."""
|
|
return cls(
|
|
pools=PoolConfig.from_bosminer(toml_conf),
|
|
mining_mode=MiningModeConfig.from_bosminer(toml_conf),
|
|
fan_mode=FanModeConfig.from_bosminer(toml_conf),
|
|
temperature=TemperatureConfig.from_bosminer(toml_conf),
|
|
)
|
|
|
|
@classmethod
|
|
def from_boser(cls, grpc_miner_conf: dict) -> "MinerConfig":
|
|
"""Constructs a MinerConfig object from gRPC configuration for BOSer."""
|
|
return cls(
|
|
pools=PoolConfig.from_boser(grpc_miner_conf),
|
|
mining_mode=MiningModeConfig.from_boser(grpc_miner_conf),
|
|
fan_mode=FanModeConfig.from_boser(grpc_miner_conf),
|
|
temperature=TemperatureConfig.from_boser(grpc_miner_conf),
|
|
)
|
|
|
|
@classmethod
|
|
def from_epic(cls, web_conf: dict) -> "MinerConfig":
|
|
"""Constructs a MinerConfig object from web configuration for ePIC miners."""
|
|
return cls(
|
|
pools=PoolConfig.from_epic(web_conf),
|
|
fan_mode=FanModeConfig.from_epic(web_conf),
|
|
temperature=TemperatureConfig.from_epic(web_conf),
|
|
mining_mode=MiningModeConfig.from_epic(web_conf),
|
|
)
|
|
|
|
@classmethod
|
|
def from_vnish(
|
|
cls, web_settings: dict, web_presets: list[dict], web_perf_summary: dict
|
|
) -> "MinerConfig":
|
|
"""Constructs a MinerConfig object from web settings for VNish miners."""
|
|
return cls(
|
|
pools=PoolConfig.from_vnish(web_settings),
|
|
fan_mode=FanModeConfig.from_vnish(web_settings),
|
|
temperature=TemperatureConfig.from_vnish(web_settings),
|
|
mining_mode=MiningModeConfig.from_vnish(
|
|
web_settings, web_presets, web_perf_summary
|
|
),
|
|
)
|
|
|
|
@classmethod
|
|
def from_auradine(cls, web_conf: dict) -> "MinerConfig":
|
|
"""Constructs a MinerConfig object from web configuration for Auradine miners."""
|
|
return cls(
|
|
pools=PoolConfig.from_api(web_conf["pools"]),
|
|
fan_mode=FanModeConfig.from_auradine(web_conf["fan"]),
|
|
mining_mode=MiningModeConfig.from_auradine(web_conf["mode"]),
|
|
)
|
|
|
|
@classmethod
|
|
def from_mara(cls, web_miner_config: dict) -> "MinerConfig":
|
|
return cls(
|
|
pools=PoolConfig.from_mara(web_miner_config),
|
|
fan_mode=FanModeConfig.from_mara(web_miner_config),
|
|
mining_mode=MiningModeConfig.from_mara(web_miner_config),
|
|
)
|
|
|
|
@classmethod
|
|
def from_espminer(cls, web_system_info: dict) -> "MinerConfig":
|
|
return cls(
|
|
pools=PoolConfig.from_espminer(web_system_info),
|
|
fan_mode=FanModeConfig.from_espminer(web_system_info),
|
|
)
|
|
|
|
@classmethod
|
|
def from_iceriver(cls, web_userpanel: dict) -> "MinerConfig":
|
|
return cls(
|
|
pools=PoolConfig.from_iceriver(web_userpanel),
|
|
)
|
|
|
|
@classmethod
|
|
def from_luxos(
|
|
cls,
|
|
rpc_tempctrl: dict,
|
|
rpc_fans: dict,
|
|
rpc_pools: dict,
|
|
rpc_groups: dict,
|
|
rpc_config: dict,
|
|
rpc_profiles: dict,
|
|
) -> "MinerConfig":
|
|
return cls(
|
|
temperature=TemperatureConfig.from_luxos(rpc_tempctrl=rpc_tempctrl),
|
|
fan_mode=FanModeConfig.from_luxos(
|
|
rpc_tempctrl=rpc_tempctrl, rpc_fans=rpc_fans
|
|
),
|
|
pools=PoolConfig.from_luxos(rpc_pools=rpc_pools, rpc_groups=rpc_groups),
|
|
mining_mode=MiningModeConfig.from_luxos(
|
|
rpc_config=rpc_config, rpc_profiles=rpc_profiles
|
|
),
|
|
)
|
|
|
|
@classmethod
|
|
def from_hammer(cls, *args, **kwargs) -> "MinerConfig":
|
|
return cls.from_am_modern(*args, **kwargs)
|
|
|
|
@classmethod
|
|
def from_btminer_v3(
|
|
cls, rpc_pools: dict, rpc_settings: dict, rpc_device_info: dict
|
|
) -> "MinerConfig":
|
|
return cls(
|
|
pools=PoolConfig.from_btminer_v3(rpc_pools=rpc_pools["msg"]),
|
|
mining_mode=MiningModeConfig.from_btminer_v3(
|
|
rpc_device_info=rpc_device_info, rpc_settings=rpc_settings
|
|
),
|
|
)
|