From 7fd3e3bada8d2c1c50a9d88fb28e947221e690fd Mon Sep 17 00:00:00 2001 From: 2Shirt <2xShirt@gmail.com> Date: Tue, 28 Jan 2020 18:04:21 -0700 Subject: [PATCH] Added Mac fan control sections --- scripts/wk/os/__init__.py | 3 +- scripts/wk/os/mac.py | 82 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 scripts/wk/os/mac.py diff --git a/scripts/wk/os/__init__.py b/scripts/wk/os/__init__.py index 1b9b21bd..dff18ac2 100644 --- a/scripts/wk/os/__init__.py +++ b/scripts/wk/os/__init__.py @@ -3,7 +3,8 @@ import platform -#if platform.system() == 'Darwin': +if platform.system() == 'Darwin': + from wk.os import mac if platform.system() == 'Linux': from wk.os import linux if platform.system() == 'Windows': diff --git a/scripts/wk/os/mac.py b/scripts/wk/os/mac.py new file mode 100644 index 00000000..5c812826 --- /dev/null +++ b/scripts/wk/os/mac.py @@ -0,0 +1,82 @@ +"""WizardKit: macOS Functions""" +# vim: sts=2 sw=2 ts=2 + +import logging +import re + +from wk.exe import run_program + + +# STATIC VARIABLES +LOG = logging.getLogger(__name__) +REGEX_FANS = re.compile(r'^.*\(bytes (?P.*)\)$') + + +# Functions +def decode_smc_bytes(text): + """Decode SMC bytes, returns int.""" + result = None + + # Get bytes + match = REGEX_FANS.match(text) + if not match: + LOG.error('Failed to decode smc output: %s', text) + raise ValueError(f'Failed to decocde smc output: {text}') + + # Convert to text + result = match.group('bytes') + result = result.replace(' ', '') + result = int(result, 16) + + # Done + return result + + +def set_fans(mode): + """Set fans to auto or max.""" + if mode == 'auto': + set_fans_auto() + elif mode == 'max': + set_fans_max() + else: + raise RuntimeError(f'Invalid fan mode: {mode}') + + +def set_fans_auto(): + """Set fans to auto.""" + LOG.info('Setting fans to auto') + cmd = ['sudo', 'smc', '-k', 'FS! ', '-w', '0000'] + run_program(cmd) + + +def set_fans_max(): + """Set fans to their max speeds.""" + LOG.info('Setting fans to max') + num_fans = 0 + + # Get number of fans + cmd = ['smc', '-k', 'FNum', '-r'] + proc = run_program(cmd) + num_fans = decode_smc_bytes(proc.stdout) + LOG.info('Found %s fans', num_fans) + + # Set all fans to forced speed + ## NOTE: mask is bit mask from right to left enabling fans + ## e.g. bit 1 is fan 0, bit 2 is fan 1, etc + ## So the mask for two fans is 0b11 or 0x3, four would be 0b111 or 0x7 + mask = f'{hex(2**num_fans - 1)[2:]:0>4}' + cmd = ['sudo', 'smc', '-k', 'FS! ', '-w', mask] + run_program(cmd) + + # Set all fans to their max speed + for fan in range(num_fans): + cmd = ['smc', '-k', f'F{fan}Mx', '-r'] + proc = run_program(cmd) + max_temp = decode_smc_bytes(proc.stdout) + LOG.info('Setting fan #%s to %s RPM', fan, str(max_temp >> 2)) + cmd = ['sudo', 'smc', '-k', f'F{fan}Tg', '-w', hex(max_temp)[2:]] + run_program(cmd) + + +if __name__ == '__main__': + print("This file is not meant to be called directly.")