feature: Add bosminer.toml parser.

This commit is contained in:
Upstream Data
2023-12-10 13:20:03 -07:00
parent 4fc57832e1
commit 43200a7354
7 changed files with 172 additions and 13 deletions

View File

@@ -119,6 +119,15 @@ class MinerConfig:
def from_inno(cls, web_pools: dict):
return cls(pools=PoolConfig.from_inno(web_pools))
@classmethod
def from_bosminer(cls, toml_conf: dict):
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),
power_scaling=PowerScalingConfig.from_bosminer(toml_conf),
)
def merge(a: dict, b: dict):
ret = {}
@@ -152,9 +161,11 @@ if __name__ == "__main__":
]
),
mining_mode=MiningModeConfig.power_tuning(3000),
temperature=TemperatureConfig(hot=100),
temperature=TemperatureConfig(hot=100, danger=110),
fan_mode=FanModeConfig.manual(minimum_fans=2, speed=70),
power_scaling=PowerScalingConfig.enabled(power_step=100, minimum_power=2400)
)
print(config)
print("WM:", config.as_wm())
print("AM Modern:", config.as_am_modern())
print("AM Old:", config.as_am_old())
@@ -164,3 +175,7 @@ if __name__ == "__main__":
print("BOS+ .toml:", config.as_bosminer())
print("BOS+ .toml as toml:")
print(toml.dumps(config.as_bosminer()))
bos_parsed = MinerConfig.from_bosminer(config.as_bosminer())
print(bos_parsed)
print(bos_parsed == config)

View File

@@ -35,6 +35,17 @@ class FanModeManual(MinerConfigValue):
minimum_fans: int = 1
speed: int = 100
@classmethod
def from_bosminer(cls, toml_fan_conf: dict):
cls_conf = {}
if toml_fan_conf.get("min_fans") is not None:
cls_conf["minimum_fans"] = toml_fan_conf["min_fans"]
if toml_fan_conf.get("speed") is not None:
cls_conf["speed"] = toml_fan_conf["speed"]
return cls(**cls_conf)
def as_am_modern(self):
return {"bitmain-fan-ctrl": True, "bitmain-fan-pwn": str(self.speed)}
@@ -74,4 +85,21 @@ class FanModeConfig(MinerConfigOption):
else:
return cls.normal()
else:
return cls.default()
return cls.default()
@classmethod
def from_bosminer(cls, toml_conf: dict):
if toml_conf.get("temp_control") is None:
return cls.default()
if toml_conf["temp_control"].get("mode") is None:
return cls.default()
mode = toml_conf["temp_control"]["mode"]
if mode == "auto":
return cls.normal()
elif mode == "manual":
if toml_conf.get("fan_control"):
return cls.manual().from_bosminer(toml_conf["fan_control"])
return cls.manual()
elif mode == "disabled":
return cls.immersion()

View File

@@ -65,13 +65,15 @@ class MiningModeHPM(MinerConfigValue):
@dataclass
class MiningModePowerTune(MinerConfigValue):
mode: str = field(init=False, default="power_tuning")
power: int
power: int = None
def as_am_modern(self):
return {"miner-mode": "0"}
def as_wm(self):
return {"mode": self.mode, self.mode: {"wattage": self.power}}
if self.power is not None:
return {"mode": self.mode, self.mode: {"wattage": self.power}}
return {}
def as_bosminer(self) -> dict:
return {"autotuning": {"enabled": True, "psu_power_limit": self.power}}
@@ -80,7 +82,7 @@ class MiningModePowerTune(MinerConfigValue):
@dataclass
class MiningModeHashrateTune(MinerConfigValue):
mode: str = field(init=False, default="hashrate_tuning")
hashrate: int
hashrate: int = None
def as_am_modern(self):
return {"miner-mode": "0"}
@@ -130,4 +132,31 @@ class MiningModeConfig(MinerConfigOption):
return cls.sleep()
elif int(work_mode) == 3:
return cls.low()
return cls.default()
return cls.default()
@classmethod
def from_bosminer(cls, toml_conf: dict):
if toml_conf.get("autotuning") is None:
return cls.default()
autotuning_conf = toml_conf["autotuning"]
if autotuning_conf.get("enabled") is None:
return cls.default()
if not autotuning_conf["enabled"]:
return cls.default()
if autotuning_conf.get("psu_power_limit") is not None:
# old autotuning conf
return cls.power_tuning(autotuning_conf["psu_power_limit"])
if autotuning_conf.get("mode") is not None:
# new autotuning conf
mode = autotuning_conf["mode"]
if mode == "power_target":
if autotuning_conf.get("power_target") is not None:
return cls.power_tuning(autotuning_conf["power_target"])
return cls.power_tuning()
if mode == "hashrate_target":
if autotuning_conf.get("hashrate_target") is not None:
return cls.hashrate_tuning(autotuning_conf["hashrate_target"])
return cls.hashrate_tuning()

View File

@@ -122,6 +122,15 @@ class Pool(MinerConfigValue):
url=web_pool["url"], user=web_pool["user"], password=web_pool["pass"]
)
@classmethod
def from_bosminer(cls, toml_pool_conf: dict):
return cls(
url=toml_pool_conf["url"],
user=toml_pool_conf["user"],
password=toml_pool_conf["pass"],
)
@dataclass
class PoolGroup(MinerConfigValue):
@@ -226,6 +235,16 @@ class PoolGroup(MinerConfigValue):
def from_inno(cls, web_pools: list):
return cls([Pool.from_inno(p) for p in web_pools])
@classmethod
def from_bosminer(cls, toml_group_conf: dict):
if toml_group_conf.get("pool") is not None:
return cls(
name=toml_group_conf["name"],
quota=toml_group_conf["quota"],
pools=[Pool.from_bosminer(p) for p in toml_group_conf["pool"]],
)
return cls()
@dataclass
class PoolConfig(MinerConfigValue):
@@ -303,3 +322,11 @@ class PoolConfig(MinerConfigValue):
return cls([PoolGroup.from_inno(web_pools)])
@classmethod
def from_bosminer(cls, toml_conf: dict):
if toml_conf.get("group") is None:
return cls()
return cls([PoolGroup.from_bosminer(g) for g in toml_conf["group"]])

View File

@@ -23,24 +23,66 @@ class PowerScalingShutdownEnabled(MinerConfigValue):
mode: str = field(init=False, default="enabled")
duration: int = None
def as_bosminer(self) -> dict:
cfg = {"shutdown_enabled": True}
if self.duration is not None:
cfg["shutdown_duration"] = self.duration
@dataclass
class PowerScalingShutdownDisabled(MinerConfigValue):
mode: str = field(init=False, default="disabled")
def as_bosminer(self) -> dict:
return {"shutdown_enabled": False}
class PowerScalingShutdown(MinerConfigOption):
enabled = PowerScalingShutdownEnabled
disabled = PowerScalingShutdownDisabled
@classmethod
def from_bosminer(cls, power_scaling_conf: dict):
sd_enabled = power_scaling_conf.get("shutdown_enabled")
if sd_enabled is not None:
if sd_enabled:
return cls.enabled(power_scaling_conf.get("shutdown_duration"))
else:
return cls.disabled()
return None
@dataclass
class PowerScalingEnabled(MinerConfigValue):
mode: str = field(init=False, default="enabled")
power_step: int = None
minimum_power: int = None
shutdown_mode: PowerScalingShutdown = None
shutdown_enabled: PowerScalingShutdown = None
@classmethod
def from_bosminer(cls, power_scaling_conf: dict):
power_step = power_scaling_conf.get("power_step")
min_power = power_scaling_conf.get("min_psu_power_limit")
sd_mode = PowerScalingShutdown.from_bosminer(power_scaling_conf)
return cls(
power_step=power_step, minimum_power=min_power, shutdown_enabled=sd_mode
)
def as_bosminer(self) -> dict:
cfg = {
"enabled": True
}
if self.power_step is not None:
cfg["power_step"] = self.power_step
if self.minimum_power is not None:
cfg["min_psu_power_limit"] = self.minimum_power
if self.shutdown_enabled is not None:
cfg = {**cfg, **self.shutdown_enabled.as_bosminer()}
return {"power_scaling": cfg}
@dataclass
class PowerScalingDisabled(MinerConfigValue):
@@ -54,3 +96,16 @@ class PowerScalingConfig(MinerConfigOption):
@classmethod
def default(cls):
return cls.disabled()
@classmethod
def from_bosminer(cls, toml_conf: dict):
power_scaling = toml_conf.get("power_scaling")
if power_scaling is not None:
enabled = power_scaling.get("enabled")
if enabled is not None:
if enabled:
return cls.enabled().from_bosminer(power_scaling)
else:
return cls.disabled()
return cls.default()

View File

@@ -37,3 +37,13 @@ class TemperatureConfig(MinerConfigValue):
if self.danger is not None:
temp_cfg["dangerous_temp"] = self.danger
return {"temp_control": temp_cfg}
@classmethod
def from_bosminer(cls, toml_conf: dict):
temp_control = toml_conf.get("temp_control")
if temp_control is not None:
return cls(
target=temp_control.get("target_temp"),
hot=temp_control.get("hot_temp"),
danger=temp_control.get("dangerous_temp"),
)

View File

@@ -297,11 +297,6 @@ class BOSMiner(BaseMiner):
return False
async def get_config(self) -> MinerConfig:
"""Gets the config for the miner and sets it as `self.config`.
Returns:
The config from `self.config`.
"""
logging.debug(f"{self}: Getting config.")
try:
@@ -316,7 +311,7 @@ class BOSMiner(BaseMiner):
(await conn.run("cat /etc/bosminer.toml")).stdout
)
logging.debug(f"{self}: Converting config file.")
cfg = MinerConfig.from_raw(toml_data)
cfg = MinerConfig.from_bosminer(toml_data)
self.config = cfg
return self.config