433 lines
14 KiB
Python
433 lines
14 KiB
Python
|
from pathlib import Path
|
||
|
from unittest.mock import Mock
|
||
|
|
||
|
import pytest
|
||
|
|
||
|
from afancontrol.arduino import (
|
||
|
ArduinoConnection,
|
||
|
ArduinoName,
|
||
|
ArduinoPin,
|
||
|
pyserial_available,
|
||
|
)
|
||
|
from afancontrol.config import (
|
||
|
Actions,
|
||
|
AlertCommands,
|
||
|
DaemonCLIConfig,
|
||
|
DaemonConfig,
|
||
|
FanName,
|
||
|
FanSpeedModifier,
|
||
|
FansTempsRelation,
|
||
|
FilteredTemp,
|
||
|
MappingName,
|
||
|
ParsedConfig,
|
||
|
ReadonlyFanName,
|
||
|
TempName,
|
||
|
TriggerConfig,
|
||
|
parse_config,
|
||
|
)
|
||
|
from afancontrol.filters import MovingMedianFilter, NullFilter
|
||
|
from afancontrol.pwmfan import (
|
||
|
ArduinoFanPWMRead,
|
||
|
ArduinoFanPWMWrite,
|
||
|
ArduinoFanSpeed,
|
||
|
FanInputDevice,
|
||
|
LinuxFanPWMRead,
|
||
|
LinuxFanPWMWrite,
|
||
|
LinuxFanSpeed,
|
||
|
PWMDevice,
|
||
|
PWMValue,
|
||
|
)
|
||
|
from afancontrol.pwmfannorm import PWMFanNorm, ReadonlyPWMFanNorm
|
||
|
from afancontrol.temp import FileTemp, HDDTemp, TempCelsius
|
||
|
|
||
|
|
||
|
@pytest.fixture
|
||
|
def pkg_conf():
|
||
|
return Path(__file__).parents[1] / "pkg" / "afancontrol.conf"
|
||
|
|
||
|
|
||
|
@pytest.fixture
|
||
|
def example_conf():
|
||
|
return Path(__file__).parents[0] / "data" / "afancontrol-example.conf"
|
||
|
|
||
|
|
||
|
def path_from_str(contents: str) -> Path:
|
||
|
p = Mock(spec=Path)
|
||
|
p.read_text.return_value = contents
|
||
|
return p
|
||
|
|
||
|
|
||
|
@pytest.mark.skipif(not pyserial_available, reason="pyserial is not installed")
|
||
|
def test_pkg_conf(pkg_conf: Path):
|
||
|
daemon_cli_config = DaemonCLIConfig(
|
||
|
pidfile=None, logfile=None, exporter_listen_host=None
|
||
|
)
|
||
|
|
||
|
parsed = parse_config(pkg_conf, daemon_cli_config)
|
||
|
assert parsed == ParsedConfig(
|
||
|
arduino_connections={},
|
||
|
daemon=DaemonConfig(
|
||
|
pidfile="/run/afancontrol.pid",
|
||
|
logfile="/var/log/afancontrol.log",
|
||
|
interval=5,
|
||
|
exporter_listen_host=None,
|
||
|
),
|
||
|
report_cmd=(
|
||
|
'printf "Subject: %s\nTo: %s\n\n%b" '
|
||
|
'"afancontrol daemon report: %REASON%" root "%MESSAGE%" | sendmail -t'
|
||
|
),
|
||
|
triggers=TriggerConfig(
|
||
|
global_commands=Actions(
|
||
|
panic=AlertCommands(enter_cmd=None, leave_cmd=None),
|
||
|
threshold=AlertCommands(enter_cmd=None, leave_cmd=None),
|
||
|
),
|
||
|
temp_commands={
|
||
|
TempName("mobo"): Actions(
|
||
|
panic=AlertCommands(enter_cmd=None, leave_cmd=None),
|
||
|
threshold=AlertCommands(enter_cmd=None, leave_cmd=None),
|
||
|
)
|
||
|
},
|
||
|
),
|
||
|
fans={
|
||
|
FanName("hdd"): PWMFanNorm(
|
||
|
fan_speed=LinuxFanSpeed(
|
||
|
FanInputDevice("/sys/class/hwmon/hwmon0/device/fan2_input")
|
||
|
),
|
||
|
pwm_read=LinuxFanPWMRead(
|
||
|
PWMDevice("/sys/class/hwmon/hwmon0/device/pwm2")
|
||
|
),
|
||
|
pwm_write=LinuxFanPWMWrite(
|
||
|
PWMDevice("/sys/class/hwmon/hwmon0/device/pwm2")
|
||
|
),
|
||
|
pwm_line_start=PWMValue(100),
|
||
|
pwm_line_end=PWMValue(240),
|
||
|
never_stop=False,
|
||
|
)
|
||
|
},
|
||
|
readonly_fans={
|
||
|
ReadonlyFanName("cpu"): ReadonlyPWMFanNorm(
|
||
|
fan_speed=LinuxFanSpeed(
|
||
|
FanInputDevice("/sys/class/hwmon/hwmon0/device/fan1_input")
|
||
|
),
|
||
|
),
|
||
|
},
|
||
|
temps={
|
||
|
TempName("mobo"): FilteredTemp(
|
||
|
temp=FileTemp(
|
||
|
"/sys/class/hwmon/hwmon0/device/temp1_input",
|
||
|
min=TempCelsius(30.0),
|
||
|
max=TempCelsius(40.0),
|
||
|
panic=None,
|
||
|
threshold=None,
|
||
|
),
|
||
|
filter=MovingMedianFilter(window_size=3),
|
||
|
)
|
||
|
},
|
||
|
mappings={
|
||
|
MappingName("1"): FansTempsRelation(
|
||
|
temps=[TempName("mobo")],
|
||
|
fans=[FanSpeedModifier(fan=FanName("hdd"), modifier=0.6)],
|
||
|
)
|
||
|
},
|
||
|
)
|
||
|
|
||
|
|
||
|
@pytest.mark.skipif(not pyserial_available, reason="pyserial is not installed")
|
||
|
def test_example_conf(example_conf: Path):
|
||
|
daemon_cli_config = DaemonCLIConfig(
|
||
|
pidfile=None, logfile=None, exporter_listen_host=None
|
||
|
)
|
||
|
|
||
|
parsed = parse_config(example_conf, daemon_cli_config)
|
||
|
assert parsed == ParsedConfig(
|
||
|
arduino_connections={
|
||
|
ArduinoName("mymicro"): ArduinoConnection(
|
||
|
ArduinoName("mymicro"), "/dev/ttyACM0", baudrate=115200, status_ttl=5
|
||
|
)
|
||
|
},
|
||
|
daemon=DaemonConfig(
|
||
|
pidfile="/run/afancontrol.pid",
|
||
|
logfile="/var/log/afancontrol.log",
|
||
|
exporter_listen_host="127.0.0.1:8083",
|
||
|
interval=5,
|
||
|
),
|
||
|
report_cmd=(
|
||
|
'printf "Subject: %s\nTo: %s\n\n%b" '
|
||
|
'"afancontrol daemon report: %REASON%" root "%MESSAGE%" | sendmail -t'
|
||
|
),
|
||
|
triggers=TriggerConfig(
|
||
|
global_commands=Actions(
|
||
|
panic=AlertCommands(enter_cmd=None, leave_cmd=None),
|
||
|
threshold=AlertCommands(enter_cmd=None, leave_cmd=None),
|
||
|
),
|
||
|
temp_commands={
|
||
|
TempName("hdds"): Actions(
|
||
|
panic=AlertCommands(enter_cmd=None, leave_cmd=None),
|
||
|
threshold=AlertCommands(enter_cmd=None, leave_cmd=None),
|
||
|
),
|
||
|
TempName("mobo"): Actions(
|
||
|
panic=AlertCommands(enter_cmd=None, leave_cmd=None),
|
||
|
threshold=AlertCommands(enter_cmd=None, leave_cmd=None),
|
||
|
),
|
||
|
},
|
||
|
),
|
||
|
fans={
|
||
|
FanName("cpu"): PWMFanNorm(
|
||
|
fan_speed=LinuxFanSpeed(
|
||
|
FanInputDevice("/sys/class/hwmon/hwmon0/device/fan1_input")
|
||
|
),
|
||
|
pwm_read=LinuxFanPWMRead(
|
||
|
PWMDevice("/sys/class/hwmon/hwmon0/device/pwm1")
|
||
|
),
|
||
|
pwm_write=LinuxFanPWMWrite(
|
||
|
PWMDevice("/sys/class/hwmon/hwmon0/device/pwm1")
|
||
|
),
|
||
|
pwm_line_start=PWMValue(100),
|
||
|
pwm_line_end=PWMValue(240),
|
||
|
never_stop=True,
|
||
|
),
|
||
|
FanName("hdd"): PWMFanNorm(
|
||
|
fan_speed=LinuxFanSpeed(
|
||
|
FanInputDevice("/sys/class/hwmon/hwmon0/device/fan2_input")
|
||
|
),
|
||
|
pwm_read=LinuxFanPWMRead(
|
||
|
PWMDevice("/sys/class/hwmon/hwmon0/device/pwm2")
|
||
|
),
|
||
|
pwm_write=LinuxFanPWMWrite(
|
||
|
PWMDevice("/sys/class/hwmon/hwmon0/device/pwm2")
|
||
|
),
|
||
|
pwm_line_start=PWMValue(100),
|
||
|
pwm_line_end=PWMValue(240),
|
||
|
never_stop=False,
|
||
|
),
|
||
|
FanName("my_arduino_fan"): PWMFanNorm(
|
||
|
fan_speed=ArduinoFanSpeed(
|
||
|
ArduinoConnection(
|
||
|
ArduinoName("mymicro"),
|
||
|
"/dev/ttyACM0", # linux
|
||
|
# "/dev/cu.usbmodem14201", # macos
|
||
|
baudrate=115200,
|
||
|
status_ttl=5,
|
||
|
),
|
||
|
tacho_pin=ArduinoPin(3),
|
||
|
),
|
||
|
pwm_read=ArduinoFanPWMRead(
|
||
|
ArduinoConnection(
|
||
|
ArduinoName("mymicro"),
|
||
|
"/dev/ttyACM0", # linux
|
||
|
# "/dev/cu.usbmodem14201", # macos
|
||
|
baudrate=115200,
|
||
|
status_ttl=5,
|
||
|
),
|
||
|
pwm_pin=ArduinoPin(9),
|
||
|
),
|
||
|
pwm_write=ArduinoFanPWMWrite(
|
||
|
ArduinoConnection(
|
||
|
ArduinoName("mymicro"),
|
||
|
"/dev/ttyACM0", # linux
|
||
|
# "/dev/cu.usbmodem14201", # macos
|
||
|
baudrate=115200,
|
||
|
status_ttl=5,
|
||
|
),
|
||
|
pwm_pin=ArduinoPin(9),
|
||
|
),
|
||
|
pwm_line_start=PWMValue(100),
|
||
|
pwm_line_end=PWMValue(240),
|
||
|
never_stop=True,
|
||
|
),
|
||
|
},
|
||
|
readonly_fans={},
|
||
|
temps={
|
||
|
TempName("hdds"): FilteredTemp(
|
||
|
temp=HDDTemp(
|
||
|
"/dev/sd?",
|
||
|
min=TempCelsius(35.0),
|
||
|
max=TempCelsius(48.0),
|
||
|
panic=TempCelsius(55.0),
|
||
|
threshold=None,
|
||
|
hddtemp_bin="hddtemp",
|
||
|
),
|
||
|
filter=NullFilter(),
|
||
|
),
|
||
|
TempName("mobo"): FilteredTemp(
|
||
|
temp=FileTemp(
|
||
|
"/sys/class/hwmon/hwmon0/device/temp1_input",
|
||
|
min=TempCelsius(30.0),
|
||
|
max=TempCelsius(40.0),
|
||
|
panic=None,
|
||
|
threshold=None,
|
||
|
),
|
||
|
filter=NullFilter(),
|
||
|
),
|
||
|
},
|
||
|
mappings={
|
||
|
MappingName("1"): FansTempsRelation(
|
||
|
temps=[TempName("mobo"), TempName("hdds")],
|
||
|
fans=[
|
||
|
FanSpeedModifier(fan=FanName("cpu"), modifier=1.0),
|
||
|
FanSpeedModifier(fan=FanName("hdd"), modifier=0.6),
|
||
|
FanSpeedModifier(fan=FanName("my_arduino_fan"), modifier=0.222),
|
||
|
],
|
||
|
),
|
||
|
MappingName("2"): FansTempsRelation(
|
||
|
temps=[TempName("hdds")],
|
||
|
fans=[FanSpeedModifier(fan=FanName("hdd"), modifier=1.0)],
|
||
|
),
|
||
|
},
|
||
|
)
|
||
|
|
||
|
|
||
|
def test_minimal_config() -> None:
|
||
|
daemon_cli_config = DaemonCLIConfig(
|
||
|
pidfile=None, logfile=None, exporter_listen_host=None
|
||
|
)
|
||
|
|
||
|
config = """
|
||
|
[daemon]
|
||
|
|
||
|
[actions]
|
||
|
|
||
|
[temp:mobo]
|
||
|
type = file
|
||
|
path = /sys/class/hwmon/hwmon0/device/temp1_input
|
||
|
|
||
|
[fan: case]
|
||
|
pwm = /sys/class/hwmon/hwmon0/device/pwm2
|
||
|
fan_input = /sys/class/hwmon/hwmon0/device/fan2_input
|
||
|
|
||
|
[mapping:1]
|
||
|
fans = case*0.6,
|
||
|
temps = mobo
|
||
|
"""
|
||
|
parsed = parse_config(path_from_str(config), daemon_cli_config)
|
||
|
assert parsed == ParsedConfig(
|
||
|
arduino_connections={},
|
||
|
daemon=DaemonConfig(
|
||
|
pidfile="/run/afancontrol.pid",
|
||
|
logfile=None,
|
||
|
exporter_listen_host=None,
|
||
|
interval=5,
|
||
|
),
|
||
|
report_cmd=(
|
||
|
'printf "Subject: %s\nTo: %s\n\n%b" '
|
||
|
'"afancontrol daemon report: %REASON%" root "%MESSAGE%" | sendmail -t'
|
||
|
),
|
||
|
triggers=TriggerConfig(
|
||
|
global_commands=Actions(
|
||
|
panic=AlertCommands(enter_cmd=None, leave_cmd=None),
|
||
|
threshold=AlertCommands(enter_cmd=None, leave_cmd=None),
|
||
|
),
|
||
|
temp_commands={
|
||
|
TempName("mobo"): Actions(
|
||
|
panic=AlertCommands(enter_cmd=None, leave_cmd=None),
|
||
|
threshold=AlertCommands(enter_cmd=None, leave_cmd=None),
|
||
|
)
|
||
|
},
|
||
|
),
|
||
|
fans={
|
||
|
FanName("case"): PWMFanNorm(
|
||
|
fan_speed=LinuxFanSpeed(
|
||
|
FanInputDevice("/sys/class/hwmon/hwmon0/device/fan2_input")
|
||
|
),
|
||
|
pwm_read=LinuxFanPWMRead(
|
||
|
PWMDevice("/sys/class/hwmon/hwmon0/device/pwm2")
|
||
|
),
|
||
|
pwm_write=LinuxFanPWMWrite(
|
||
|
PWMDevice("/sys/class/hwmon/hwmon0/device/pwm2")
|
||
|
),
|
||
|
pwm_line_start=PWMValue(100),
|
||
|
pwm_line_end=PWMValue(240),
|
||
|
never_stop=True,
|
||
|
)
|
||
|
},
|
||
|
readonly_fans={},
|
||
|
temps={
|
||
|
TempName("mobo"): FilteredTemp(
|
||
|
temp=FileTemp(
|
||
|
"/sys/class/hwmon/hwmon0/device/temp1_input",
|
||
|
min=None,
|
||
|
max=None,
|
||
|
panic=None,
|
||
|
threshold=None,
|
||
|
),
|
||
|
filter=NullFilter(),
|
||
|
)
|
||
|
},
|
||
|
mappings={
|
||
|
MappingName("1"): FansTempsRelation(
|
||
|
temps=[TempName("mobo")],
|
||
|
fans=[FanSpeedModifier(fan=FanName("case"), modifier=0.6)],
|
||
|
)
|
||
|
},
|
||
|
)
|
||
|
|
||
|
|
||
|
def test_readonly_config() -> None:
|
||
|
daemon_cli_config = DaemonCLIConfig(
|
||
|
pidfile=None, logfile=None, exporter_listen_host=None
|
||
|
)
|
||
|
|
||
|
config = """
|
||
|
[daemon]
|
||
|
|
||
|
[actions]
|
||
|
|
||
|
[temp:mobo]
|
||
|
type = file
|
||
|
path = /sys/class/hwmon/hwmon0/device/temp1_input
|
||
|
|
||
|
[readonly_fan: cpu]
|
||
|
pwm = /sys/class/hwmon/hwmon0/device/pwm1
|
||
|
fan_input = /sys/class/hwmon/hwmon0/device/fan1_input
|
||
|
"""
|
||
|
parsed = parse_config(path_from_str(config), daemon_cli_config)
|
||
|
assert parsed == ParsedConfig(
|
||
|
arduino_connections={},
|
||
|
daemon=DaemonConfig(
|
||
|
pidfile="/run/afancontrol.pid",
|
||
|
logfile=None,
|
||
|
exporter_listen_host=None,
|
||
|
interval=5,
|
||
|
),
|
||
|
report_cmd=(
|
||
|
'printf "Subject: %s\nTo: %s\n\n%b" '
|
||
|
'"afancontrol daemon report: %REASON%" root "%MESSAGE%" | sendmail -t'
|
||
|
),
|
||
|
triggers=TriggerConfig(
|
||
|
global_commands=Actions(
|
||
|
panic=AlertCommands(enter_cmd=None, leave_cmd=None),
|
||
|
threshold=AlertCommands(enter_cmd=None, leave_cmd=None),
|
||
|
),
|
||
|
temp_commands={
|
||
|
TempName("mobo"): Actions(
|
||
|
panic=AlertCommands(enter_cmd=None, leave_cmd=None),
|
||
|
threshold=AlertCommands(enter_cmd=None, leave_cmd=None),
|
||
|
)
|
||
|
},
|
||
|
),
|
||
|
fans={},
|
||
|
readonly_fans={
|
||
|
ReadonlyFanName("cpu"): ReadonlyPWMFanNorm(
|
||
|
fan_speed=LinuxFanSpeed(
|
||
|
FanInputDevice("/sys/class/hwmon/hwmon0/device/fan1_input")
|
||
|
),
|
||
|
pwm_read=LinuxFanPWMRead(
|
||
|
PWMDevice("/sys/class/hwmon/hwmon0/device/pwm1")
|
||
|
),
|
||
|
)
|
||
|
},
|
||
|
temps={
|
||
|
TempName("mobo"): FilteredTemp(
|
||
|
temp=FileTemp(
|
||
|
"/sys/class/hwmon/hwmon0/device/temp1_input",
|
||
|
min=None,
|
||
|
max=None,
|
||
|
panic=None,
|
||
|
threshold=None,
|
||
|
),
|
||
|
filter=NullFilter(),
|
||
|
)
|
||
|
},
|
||
|
mappings={},
|
||
|
)
|