feature: add boser config parsing.
This commit is contained in:
@@ -99,13 +99,13 @@ class MinerConfig:
|
||||
**self.power_scaling.as_bosminer(),
|
||||
}
|
||||
|
||||
def as_bos_grpc(self, user_suffix: str = None) -> dict:
|
||||
def as_boser(self, user_suffix: str = None) -> dict:
|
||||
return {
|
||||
**self.fan_mode.as_bos_grpc(),
|
||||
**self.temperature.as_bos_grpc(),
|
||||
**self.mining_mode.as_bos_grpc(),
|
||||
**self.pools.as_bos_grpc(user_suffix=user_suffix),
|
||||
**self.power_scaling.as_bos_grpc(),
|
||||
**self.fan_mode.as_boser(),
|
||||
**self.temperature.as_boser(),
|
||||
**self.mining_mode.as_boser(),
|
||||
**self.pools.as_boser(user_suffix=user_suffix),
|
||||
**self.power_scaling.as_boser(),
|
||||
}
|
||||
|
||||
def as_epic(self, user_suffix: str = None) -> dict:
|
||||
@@ -161,6 +161,16 @@ class MinerConfig:
|
||||
power_scaling=PowerScalingConfig.from_bosminer(toml_conf),
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_boser(cls, grpc_miner_conf: dict) -> "MinerConfig":
|
||||
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),
|
||||
power_scaling=PowerScalingConfig.from_boser(grpc_miner_conf),
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_epic(cls, web_conf: dict) -> "MinerConfig":
|
||||
return cls(
|
||||
|
||||
@@ -44,8 +44,8 @@ class MinerConfigOption(Enum):
|
||||
def as_bosminer(self) -> dict:
|
||||
return self.value.as_bosminer()
|
||||
|
||||
def as_bos_grpc(self) -> dict:
|
||||
return self.value.as_bos_grpc()
|
||||
def as_boser(self) -> dict:
|
||||
return self.value.as_boser()
|
||||
|
||||
def as_epic(self) -> dict:
|
||||
return self.value.as_epic()
|
||||
@@ -91,7 +91,7 @@ class MinerConfigValue:
|
||||
def as_bosminer(self) -> dict:
|
||||
return {}
|
||||
|
||||
def as_bos_grpc(self) -> dict:
|
||||
def as_boser(self) -> dict:
|
||||
return {}
|
||||
|
||||
def as_epic(self) -> dict:
|
||||
|
||||
@@ -182,3 +182,23 @@ class FanModeConfig(MinerConfigOption):
|
||||
return cls.manual().from_vnish(web_settings["miner"]["cooling"])
|
||||
elif mode == "immers":
|
||||
return cls.immersion()
|
||||
|
||||
@classmethod
|
||||
def from_boser(cls, grpc_miner_conf: dict):
|
||||
try:
|
||||
temperature_conf = grpc_miner_conf["temperature"]
|
||||
except LookupError:
|
||||
return cls.default()
|
||||
|
||||
keys = temperature_conf.keys()
|
||||
if "auto" in keys:
|
||||
if "minimumRequiredFans" in keys:
|
||||
return cls.normal(temperature_conf["minimumRequiredFans"])
|
||||
return cls.normal()
|
||||
if "manual" in keys:
|
||||
conf = {}
|
||||
if "fanSpeedRatio" in temperature_conf["manual"].keys():
|
||||
conf["speed"] = int(temperature_conf["manual"]["fanSpeedRatio"])
|
||||
if "minimumRequiredFans" in keys:
|
||||
conf["minimum_fans"] = int(temperature_conf["minimumRequiredFans"])
|
||||
return cls.manual(**conf)
|
||||
|
||||
@@ -260,3 +260,33 @@ class MiningModeConfig(MinerConfigOption):
|
||||
return MiningModeManual.from_vnish(mode_settings)
|
||||
else:
|
||||
return cls.power_tuning(int(mode_settings["preset"]))
|
||||
|
||||
@classmethod
|
||||
def from_boser(cls, grpc_miner_conf: dict):
|
||||
try:
|
||||
tuner_conf = grpc_miner_conf["tuner"]
|
||||
if not tuner_conf.get("enabled", False):
|
||||
return cls.default()
|
||||
except LookupError:
|
||||
return cls.default()
|
||||
|
||||
if tuner_conf.get("tunerMode") is not None:
|
||||
if tuner_conf["tunerMode"] == 1:
|
||||
if tuner_conf.get("powerTarget") is not None:
|
||||
return cls.power_tuning(tuner_conf["powerTarget"]["watt"])
|
||||
return cls.power_tuning()
|
||||
|
||||
if tuner_conf["tunerMode"] == 2:
|
||||
if tuner_conf.get("hashrateTarget") is not None:
|
||||
return cls.hashrate_tuning(
|
||||
int(tuner_conf["hashrateTarget"]["terahashPerSecond"])
|
||||
)
|
||||
return cls.hashrate_tuning()
|
||||
|
||||
if tuner_conf.get("powerTarget") is not None:
|
||||
return cls.power_tuning(tuner_conf["powerTarget"]["watt"])
|
||||
|
||||
if tuner_conf.get("hashrateTarget") is not None:
|
||||
return cls.hashrate_tuning(
|
||||
int(tuner_conf["hashrateTarget"]["terahashPerSecond"])
|
||||
)
|
||||
|
||||
@@ -149,6 +149,14 @@ class Pool(MinerConfigValue):
|
||||
password=web_pool["pass"],
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_boser(cls, grpc_pool: dict) -> "Pool":
|
||||
return cls(
|
||||
url=grpc_pool["url"],
|
||||
user=grpc_pool["user"],
|
||||
password=grpc_pool["password"],
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class PoolGroup(MinerConfigValue):
|
||||
@@ -287,6 +295,19 @@ class PoolGroup(MinerConfigValue):
|
||||
def from_vnish(cls, web_settings_pools: dict) -> "PoolGroup":
|
||||
return cls([Pool.from_vnish(p) for p in web_settings_pools])
|
||||
|
||||
@classmethod
|
||||
def from_boser(cls, grpc_pool_group: dict):
|
||||
try:
|
||||
return cls(
|
||||
pools=[Pool.from_boser(p) for p in grpc_pool_group["pools"]],
|
||||
name=grpc_pool_group["name"],
|
||||
quota=grpc_pool_group["quota"]["value"]
|
||||
if grpc_pool_group.get("quota") is not None
|
||||
else 1,
|
||||
)
|
||||
except LookupError:
|
||||
return cls()
|
||||
|
||||
|
||||
@dataclass
|
||||
class PoolConfig(MinerConfigValue):
|
||||
@@ -349,7 +370,7 @@ class PoolConfig(MinerConfigValue):
|
||||
}
|
||||
return {"group": [PoolGroup().as_bosminer()]}
|
||||
|
||||
def as_bos_grpc(self, user_suffix: str = None) -> dict:
|
||||
def as_boser(self, user_suffix: str = None) -> dict:
|
||||
return {}
|
||||
|
||||
@classmethod
|
||||
@@ -394,3 +415,15 @@ class PoolConfig(MinerConfigValue):
|
||||
return cls([PoolGroup.from_vnish(web_settings["miner"]["pools"])])
|
||||
except LookupError:
|
||||
return cls()
|
||||
|
||||
@classmethod
|
||||
def from_boser(cls, grpc_miner_conf: dict):
|
||||
try:
|
||||
return cls(
|
||||
groups=[
|
||||
PoolGroup.from_boser(group)
|
||||
for group in grpc_miner_conf["poolGroups"]
|
||||
]
|
||||
)
|
||||
except LookupError:
|
||||
return cls()
|
||||
|
||||
@@ -37,7 +37,7 @@ class PowerScalingShutdownEnabled(MinerConfigValue):
|
||||
|
||||
return cfg
|
||||
|
||||
def as_bos_grpc(self) -> dict:
|
||||
def as_boser(self) -> dict:
|
||||
cfg = {"enable_shutdown ": True}
|
||||
|
||||
if self.duration is not None:
|
||||
@@ -57,7 +57,7 @@ class PowerScalingShutdownDisabled(MinerConfigValue):
|
||||
def as_bosminer(self) -> dict:
|
||||
return {"shutdown_enabled": False}
|
||||
|
||||
def as_bos_grpc(self) -> dict:
|
||||
def as_boser(self) -> dict:
|
||||
return {"enable_shutdown ": False}
|
||||
|
||||
|
||||
@@ -88,6 +88,19 @@ class PowerScalingShutdown(MinerConfigOption):
|
||||
return cls.disabled()
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def from_boser(cls, power_scaling_conf: dict):
|
||||
sd_enabled = power_scaling_conf.get("shutdownEnabled")
|
||||
if sd_enabled is not None:
|
||||
if sd_enabled:
|
||||
try:
|
||||
return cls.enabled(power_scaling_conf["shutdownDuration"]["hours"])
|
||||
except KeyError:
|
||||
return cls.enabled()
|
||||
else:
|
||||
return cls.disabled()
|
||||
return None
|
||||
|
||||
|
||||
@dataclass
|
||||
class PowerScalingEnabled(MinerConfigValue):
|
||||
@@ -133,7 +146,7 @@ class PowerScalingEnabled(MinerConfigValue):
|
||||
|
||||
return {"power_scaling": cfg}
|
||||
|
||||
def as_bos_grpc(self) -> dict:
|
||||
def as_boser(self) -> dict:
|
||||
cfg = {"enable": True}
|
||||
target_conf = {}
|
||||
if self.power_step is not None:
|
||||
@@ -144,7 +157,7 @@ class PowerScalingEnabled(MinerConfigValue):
|
||||
cfg["target"] = DpsTarget(power_target=DpsPowerTarget(**target_conf))
|
||||
|
||||
if self.shutdown_enabled is not None:
|
||||
cfg = {**cfg, **self.shutdown_enabled.as_bos_grpc()}
|
||||
cfg = {**cfg, **self.shutdown_enabled.as_boser()}
|
||||
|
||||
return {"dps": cfg}
|
||||
|
||||
@@ -187,3 +200,21 @@ class PowerScalingConfig(MinerConfigOption):
|
||||
return cls.disabled()
|
||||
|
||||
return cls.default()
|
||||
|
||||
@classmethod
|
||||
def from_boser(cls, grpc_miner_conf: dict):
|
||||
try:
|
||||
dps_conf = grpc_miner_conf["dps"]
|
||||
if not dps_conf.get("enabled", False):
|
||||
return cls.disabled()
|
||||
except LookupError:
|
||||
return cls.default()
|
||||
|
||||
conf = {}
|
||||
|
||||
conf["shutdown_enabled"] = PowerScalingShutdown.from_boser(dps_conf)
|
||||
if dps_conf.get("minPowerTarget") is not None:
|
||||
conf["minimum_power"] = dps_conf["minPowerTarget"]["watt"]
|
||||
if dps_conf.get("powerStep") is not None:
|
||||
conf["power_step"] = dps_conf["powerStep"]["watt"]
|
||||
return cls.enabled(**conf)
|
||||
|
||||
@@ -80,3 +80,34 @@ class TemperatureConfig(MinerConfigValue):
|
||||
except KeyError:
|
||||
pass
|
||||
return cls()
|
||||
|
||||
@classmethod
|
||||
def from_boser(cls, grpc_miner_conf: dict):
|
||||
try:
|
||||
temperature_conf = grpc_miner_conf["temperature"]
|
||||
except KeyError:
|
||||
return cls.default()
|
||||
|
||||
root_key = None
|
||||
for key in ["auto", "manual", "disabled"]:
|
||||
if key in temperature_conf.keys():
|
||||
root_key = key
|
||||
break
|
||||
if root_key is None:
|
||||
return cls.default()
|
||||
|
||||
conf = {}
|
||||
keys = temperature_conf[root_key].keys()
|
||||
if "targetTemperature" in keys:
|
||||
conf["target"] = int(
|
||||
temperature_conf[root_key]["targetTemperature"]["degreeC"]
|
||||
)
|
||||
if "hotTemperature" in keys:
|
||||
conf["hot"] = int(temperature_conf[root_key]["hotTemperature"]["degreeC"])
|
||||
if "dangerousTemperature" in keys:
|
||||
conf["danger"] = int(
|
||||
temperature_conf[root_key]["dangerousTemperature"]["degreeC"]
|
||||
)
|
||||
|
||||
return cls(**conf)
|
||||
return cls.default()
|
||||
|
||||
@@ -908,23 +908,9 @@ class BOSer(BaseMiner):
|
||||
return False
|
||||
|
||||
async def get_config(self) -> MinerConfig:
|
||||
logging.debug(f"{self}: Getting config.")
|
||||
grpc_conf = await self.web.grpc.get_miner_configuration()
|
||||
|
||||
try:
|
||||
conn = await self._get_ssh_connection()
|
||||
except ConnectionError:
|
||||
conn = None
|
||||
|
||||
if conn:
|
||||
async with conn:
|
||||
# good ol' BBB compatibility :/
|
||||
toml_data = toml.loads(
|
||||
(await conn.run("cat /etc/bosminer.toml")).stdout
|
||||
)
|
||||
logging.debug(f"{self}: Converting config file.")
|
||||
cfg = MinerConfig.from_bosminer(toml_data)
|
||||
self.config = cfg
|
||||
return self.config
|
||||
return MinerConfig.from_boser(grpc_conf)
|
||||
|
||||
async def send_config(self, config: MinerConfig, user_suffix: str = None) -> None:
|
||||
logging.debug(f"{self}: Sending config.")
|
||||
|
||||
@@ -43,6 +43,7 @@ class BOSerGRPCAPI:
|
||||
self.ip = ip
|
||||
self.username = "root"
|
||||
self.pwd = pwd
|
||||
self.port = 50051
|
||||
self._auth = None
|
||||
self._auth_time = datetime.now()
|
||||
|
||||
@@ -76,7 +77,7 @@ class BOSerGRPCAPI:
|
||||
metadata = []
|
||||
if auth:
|
||||
metadata.append(("authorization", await self.auth()))
|
||||
async with Channel(self.ip, 50051) as c:
|
||||
async with Channel(self.ip, self.port) as c:
|
||||
endpoint = getattr(BOSMinerGRPCStub(c), command)
|
||||
if endpoint is None:
|
||||
if not ignore_errors:
|
||||
@@ -93,7 +94,7 @@ class BOSerGRPCAPI:
|
||||
return self._auth
|
||||
|
||||
async def _get_auth(self):
|
||||
async with Channel(self.ip, 50051) as c:
|
||||
async with Channel(self.ip, self.port) as c:
|
||||
req = LoginRequest(username=self.username, password=self.pwd)
|
||||
async with c.request(
|
||||
"/braiins.bos.v1.AuthenticationService/Login",
|
||||
|
||||
Reference in New Issue
Block a user