Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 36 additions & 19 deletions pyasic/config/fans.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------
from __future__ import annotations

from typing import TypeVar
from typing import Any, TypeVar

from pydantic import Field

Expand Down Expand Up @@ -337,28 +337,45 @@ def from_vnish(cls, web_settings: dict):

@classmethod
def from_boser(cls, grpc_miner_conf: dict):
try:
temperature_conf = grpc_miner_conf["temperature"]
except LookupError:
temperature_conf = grpc_miner_conf.get("temperature")
if not isinstance(temperature_conf, dict):
return cls.default()

keys = temperature_conf.keys()
if "auto" in keys:
if "minimumRequiredFans" in keys:
return cls.normal(minimum_fans=temperature_conf["minimumRequiredFans"])
def _maybe_int(value: Any) -> int | None:
if isinstance(value, (int, float, str)) and value != "":
try:
return int(value)
except (TypeError, ValueError):
return None
return None

min_fans = _maybe_int(temperature_conf.get("minimumRequiredFans"))

def _build_conf(conf_section: object) -> dict:
conf: dict = {}
if isinstance(conf_section, dict):
speed = _maybe_int(conf_section.get("fanSpeedRatio"))
if speed is not None:
conf["speed"] = speed
if min_fans is not None:
conf["minimum_fans"] = min_fans
return conf

if "auto" in temperature_conf:
if min_fans is not None:
return cls.normal(minimum_fans=min_fans)
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)
if "disabled" in keys:
conf = {}
if "fanSpeedRatio" in temperature_conf["disabled"].keys():
conf["speed"] = int(temperature_conf["disabled"]["fanSpeedRatio"])

if "manual" in temperature_conf:
conf = _build_conf(temperature_conf.get("manual"))
return cls.manual(**conf)

if "disabled" in temperature_conf:
conf = _build_conf(temperature_conf.get("disabled"))
if conf.get("speed") is not None:
return cls.manual(**conf)
return cls.immersion()

return cls.default()

@classmethod
Expand Down
44 changes: 28 additions & 16 deletions pyasic/config/temperature.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,32 +114,44 @@ def from_vnish(cls, web_settings: dict) -> TemperatureConfig:

@classmethod
def from_boser(cls, grpc_miner_conf: dict) -> TemperatureConfig:
try:
temperature_conf = grpc_miner_conf["temperature"]
except KeyError:
temperature_conf = grpc_miner_conf.get("temperature")
if not isinstance(temperature_conf, dict):
return cls.default()

root_key = None
for key in ["auto", "manual", "disabled"]:
if key in temperature_conf.keys():
if key in temperature_conf:
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"]
)
raw_conf = temperature_conf.get(root_key) or {}
if not isinstance(raw_conf, dict):
return cls.default()

def _read_temp(temp_block: object) -> int | None:
if isinstance(temp_block, dict):
temp_value = temp_block.get("degreeC")
else:
temp_value = temp_block
try:
return int(temp_value) if temp_value is not None else None
except (TypeError, ValueError):
return None

conf: dict = {}
target_temp = _read_temp(raw_conf.get("targetTemperature"))
if target_temp is not None:
conf["target"] = target_temp
hot_temp = _read_temp(raw_conf.get("hotTemperature"))
if hot_temp is not None:
conf["hot"] = hot_temp
danger_temp = _read_temp(raw_conf.get("dangerousTemperature"))
if danger_temp is not None:
conf["danger"] = danger_temp

if conf:
return cls(**conf)
return cls.default()

Expand Down
37 changes: 37 additions & 0 deletions tests/config_tests/test_boser_25_01.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import unittest

from pyasic.config import FanModeConfig, TemperatureConfig


class TestBoserConfig25_01(unittest.TestCase):
def test_fan_mode_handles_null_temperature(self):
grpc_conf = {"temperature": None}
self.assertEqual(FanModeConfig.default(), FanModeConfig.from_boser(grpc_conf))

def test_fan_mode_handles_empty_manual(self):
grpc_conf = {"temperature": {"manual": None, "minimumRequiredFans": None}}
self.assertEqual(FanModeConfig.manual(), FanModeConfig.from_boser(grpc_conf))

def test_fan_mode_auto_with_missing_min_fans(self):
grpc_conf = {"temperature": {"auto": {}, "minimumRequiredFans": None}}
self.assertEqual(FanModeConfig.normal(), FanModeConfig.from_boser(grpc_conf))

def test_fan_mode_disabled_without_speed_defaults_to_immersion(self):
grpc_conf = {"temperature": {"disabled": {}, "minimumRequiredFans": 0}}
self.assertEqual(FanModeConfig.immersion(), FanModeConfig.from_boser(grpc_conf))

def test_temperature_allows_partial_payload(self):
grpc_conf = {"temperature": {"auto": {"targetTemperature": {"degreeC": 70}}}}
self.assertEqual(
TemperatureConfig(target=70), TemperatureConfig.from_boser(grpc_conf)
)

def test_temperature_returns_default_on_null(self):
grpc_conf = {"temperature": None}
self.assertEqual(
TemperatureConfig.default(), TemperatureConfig.from_boser(grpc_conf)
)


if __name__ == "__main__":
unittest.main()