# ------------------------------------------------------------------------------ # 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 pydantic import BaseModel, Field from pyasic.config.fans import FanMode, FanModeConfig, FanModeNormal from pyasic.config.mining import MiningMode, 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: FanMode = Field(default_factory=FanModeConfig.default) temperature: TemperatureConfig = Field(default_factory=TemperatureConfig.default) mining_mode: MiningMode = Field(default_factory=MiningModeConfig.default) def __getitem__(self, item): 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) -> 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_wm(self, user_suffix: str = 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_am_old(self, user_suffix: str = 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) -> 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) -> 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) -> 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) -> 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) -> 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) -> 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) -> 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) -> 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_bitaxe(self, user_suffix: str = None) -> dict: return { **self.fan_mode.as_bitaxe(), **self.temperature.as_bitaxe(), **self.mining_mode.as_bitaxe(), **self.pools.as_bitaxe(user_suffix=user_suffix), } def as_luxos(self, user_suffix: str = 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) -> 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_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_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]) -> "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), ) @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_bitaxe(cls, web_system_info: dict) -> "MinerConfig": return cls( pools=PoolConfig.from_bitaxe(web_system_info), fan_mode=FanModeConfig.from_bitaxe(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_hiveon_modern(cls, web_conf: dict) -> "MinerConfig": return cls.from_am_modern(web_conf)