feature: add boser config parsing.
This commit is contained in:
@@ -99,13 +99,13 @@ class MinerConfig:
|
|||||||
**self.power_scaling.as_bosminer(),
|
**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 {
|
return {
|
||||||
**self.fan_mode.as_bos_grpc(),
|
**self.fan_mode.as_boser(),
|
||||||
**self.temperature.as_bos_grpc(),
|
**self.temperature.as_boser(),
|
||||||
**self.mining_mode.as_bos_grpc(),
|
**self.mining_mode.as_boser(),
|
||||||
**self.pools.as_bos_grpc(user_suffix=user_suffix),
|
**self.pools.as_boser(user_suffix=user_suffix),
|
||||||
**self.power_scaling.as_bos_grpc(),
|
**self.power_scaling.as_boser(),
|
||||||
}
|
}
|
||||||
|
|
||||||
def as_epic(self, user_suffix: str = None) -> dict:
|
def as_epic(self, user_suffix: str = None) -> dict:
|
||||||
@@ -161,6 +161,16 @@ class MinerConfig:
|
|||||||
power_scaling=PowerScalingConfig.from_bosminer(toml_conf),
|
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
|
@classmethod
|
||||||
def from_epic(cls, web_conf: dict) -> "MinerConfig":
|
def from_epic(cls, web_conf: dict) -> "MinerConfig":
|
||||||
return cls(
|
return cls(
|
||||||
|
|||||||
@@ -44,8 +44,8 @@ class MinerConfigOption(Enum):
|
|||||||
def as_bosminer(self) -> dict:
|
def as_bosminer(self) -> dict:
|
||||||
return self.value.as_bosminer()
|
return self.value.as_bosminer()
|
||||||
|
|
||||||
def as_bos_grpc(self) -> dict:
|
def as_boser(self) -> dict:
|
||||||
return self.value.as_bos_grpc()
|
return self.value.as_boser()
|
||||||
|
|
||||||
def as_epic(self) -> dict:
|
def as_epic(self) -> dict:
|
||||||
return self.value.as_epic()
|
return self.value.as_epic()
|
||||||
@@ -91,7 +91,7 @@ class MinerConfigValue:
|
|||||||
def as_bosminer(self) -> dict:
|
def as_bosminer(self) -> dict:
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
def as_bos_grpc(self) -> dict:
|
def as_boser(self) -> dict:
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
def as_epic(self) -> dict:
|
def as_epic(self) -> dict:
|
||||||
|
|||||||
@@ -182,3 +182,23 @@ class FanModeConfig(MinerConfigOption):
|
|||||||
return cls.manual().from_vnish(web_settings["miner"]["cooling"])
|
return cls.manual().from_vnish(web_settings["miner"]["cooling"])
|
||||||
elif mode == "immers":
|
elif mode == "immers":
|
||||||
return cls.immersion()
|
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)
|
return MiningModeManual.from_vnish(mode_settings)
|
||||||
else:
|
else:
|
||||||
return cls.power_tuning(int(mode_settings["preset"]))
|
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"],
|
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
|
@dataclass
|
||||||
class PoolGroup(MinerConfigValue):
|
class PoolGroup(MinerConfigValue):
|
||||||
@@ -287,6 +295,19 @@ class PoolGroup(MinerConfigValue):
|
|||||||
def from_vnish(cls, web_settings_pools: dict) -> "PoolGroup":
|
def from_vnish(cls, web_settings_pools: dict) -> "PoolGroup":
|
||||||
return cls([Pool.from_vnish(p) for p in web_settings_pools])
|
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
|
@dataclass
|
||||||
class PoolConfig(MinerConfigValue):
|
class PoolConfig(MinerConfigValue):
|
||||||
@@ -349,7 +370,7 @@ class PoolConfig(MinerConfigValue):
|
|||||||
}
|
}
|
||||||
return {"group": [PoolGroup().as_bosminer()]}
|
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 {}
|
return {}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -394,3 +415,15 @@ class PoolConfig(MinerConfigValue):
|
|||||||
return cls([PoolGroup.from_vnish(web_settings["miner"]["pools"])])
|
return cls([PoolGroup.from_vnish(web_settings["miner"]["pools"])])
|
||||||
except LookupError:
|
except LookupError:
|
||||||
return cls()
|
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
|
return cfg
|
||||||
|
|
||||||
def as_bos_grpc(self) -> dict:
|
def as_boser(self) -> dict:
|
||||||
cfg = {"enable_shutdown ": True}
|
cfg = {"enable_shutdown ": True}
|
||||||
|
|
||||||
if self.duration is not None:
|
if self.duration is not None:
|
||||||
@@ -57,7 +57,7 @@ class PowerScalingShutdownDisabled(MinerConfigValue):
|
|||||||
def as_bosminer(self) -> dict:
|
def as_bosminer(self) -> dict:
|
||||||
return {"shutdown_enabled": False}
|
return {"shutdown_enabled": False}
|
||||||
|
|
||||||
def as_bos_grpc(self) -> dict:
|
def as_boser(self) -> dict:
|
||||||
return {"enable_shutdown ": False}
|
return {"enable_shutdown ": False}
|
||||||
|
|
||||||
|
|
||||||
@@ -88,6 +88,19 @@ class PowerScalingShutdown(MinerConfigOption):
|
|||||||
return cls.disabled()
|
return cls.disabled()
|
||||||
return None
|
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
|
@dataclass
|
||||||
class PowerScalingEnabled(MinerConfigValue):
|
class PowerScalingEnabled(MinerConfigValue):
|
||||||
@@ -133,7 +146,7 @@ class PowerScalingEnabled(MinerConfigValue):
|
|||||||
|
|
||||||
return {"power_scaling": cfg}
|
return {"power_scaling": cfg}
|
||||||
|
|
||||||
def as_bos_grpc(self) -> dict:
|
def as_boser(self) -> dict:
|
||||||
cfg = {"enable": True}
|
cfg = {"enable": True}
|
||||||
target_conf = {}
|
target_conf = {}
|
||||||
if self.power_step is not None:
|
if self.power_step is not None:
|
||||||
@@ -144,7 +157,7 @@ class PowerScalingEnabled(MinerConfigValue):
|
|||||||
cfg["target"] = DpsTarget(power_target=DpsPowerTarget(**target_conf))
|
cfg["target"] = DpsTarget(power_target=DpsPowerTarget(**target_conf))
|
||||||
|
|
||||||
if self.shutdown_enabled is not None:
|
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}
|
return {"dps": cfg}
|
||||||
|
|
||||||
@@ -187,3 +200,21 @@ class PowerScalingConfig(MinerConfigOption):
|
|||||||
return cls.disabled()
|
return cls.disabled()
|
||||||
|
|
||||||
return cls.default()
|
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:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
return cls()
|
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
|
return False
|
||||||
|
|
||||||
async def get_config(self) -> MinerConfig:
|
async def get_config(self) -> MinerConfig:
|
||||||
logging.debug(f"{self}: Getting config.")
|
grpc_conf = await self.web.grpc.get_miner_configuration()
|
||||||
|
|
||||||
try:
|
return MinerConfig.from_boser(grpc_conf)
|
||||||
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
|
|
||||||
|
|
||||||
async def send_config(self, config: MinerConfig, user_suffix: str = None) -> None:
|
async def send_config(self, config: MinerConfig, user_suffix: str = None) -> None:
|
||||||
logging.debug(f"{self}: Sending config.")
|
logging.debug(f"{self}: Sending config.")
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ class BOSerGRPCAPI:
|
|||||||
self.ip = ip
|
self.ip = ip
|
||||||
self.username = "root"
|
self.username = "root"
|
||||||
self.pwd = pwd
|
self.pwd = pwd
|
||||||
|
self.port = 50051
|
||||||
self._auth = None
|
self._auth = None
|
||||||
self._auth_time = datetime.now()
|
self._auth_time = datetime.now()
|
||||||
|
|
||||||
@@ -76,7 +77,7 @@ class BOSerGRPCAPI:
|
|||||||
metadata = []
|
metadata = []
|
||||||
if auth:
|
if auth:
|
||||||
metadata.append(("authorization", await self.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)
|
endpoint = getattr(BOSMinerGRPCStub(c), command)
|
||||||
if endpoint is None:
|
if endpoint is None:
|
||||||
if not ignore_errors:
|
if not ignore_errors:
|
||||||
@@ -93,7 +94,7 @@ class BOSerGRPCAPI:
|
|||||||
return self._auth
|
return self._auth
|
||||||
|
|
||||||
async def _get_auth(self):
|
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)
|
req = LoginRequest(username=self.username, password=self.pwd)
|
||||||
async with c.request(
|
async with c.request(
|
||||||
"/braiins.bos.v1.AuthenticationService/Login",
|
"/braiins.bos.v1.AuthenticationService/Login",
|
||||||
|
|||||||
Reference in New Issue
Block a user