<?php namespace App\Command; use App\Application; use GetOpt\GetOpt; use Hugga\Console; use Hugga\Input\Question\Choice; use Hugga\Input\Question\Confirmation; class Config extends AbstractCommand { protected $name = 'config'; protected $description = 'Generate or update fan configuration'; public function __construct(Application $app, Console $console) { parent::__construct($app, $console); } public function handle(GetOpt $getOpt): int { if (posix_getuid() !== 0) { $this->warn('This programm has to run as root'); return 1; } if ($this->getOption('quiet')) { $this->warn('This command requires user interaction'); return 1; } $fanConfig = $this->app->fanConfig; if (!$fanConfig->hasFans()) { if (!$this->initializeConfig()) { return 1; } } $actions = new Choice([ 'edit a fan', 'add a sensor', 'edit a sensor', 'add a rule', 'edit a rule', 'save and exit', 'exit without saving', ], 'What next?', 'save and exit'); do { $answer = $this->console->ask($actions); switch ($answer) { case 'exit without saving': break 2; case 'save and exit': // $fanConfig->save(); break 2; default: $this->info('not implemented'); } } while (true); // - edit a fan // - add a sensor // - edit a sensor // - add a rule // - edit a rule // - save and leave // - leave without saving return 0; } protected function initializeConfig() { $fanConfig = $this->app->fanConfig; $this->info('No fans configured. Detecting fans...'); $fans = $this->detectControllableFans(); if (count($fans) > 0) { // for each fan // ask if it should be added // ask for a name // test min speed // ask for a pwm limit // add the fan to the config $fanConfig->setFans($fans); $fanConfig->save(); return true; } $this->error('We could not find any fan to control.'); return false; } protected function detectControllableFans(): array { $fans = []; $inputs = glob(HWMON_PATH . '/hwmon*/fan*_input'); $inputs = array_reduce($inputs, function ($inputs, $input) { if (!preg_match('~(hwmon(\d+)/(fan\d+))_input$~', $input, $match)) { return $inputs; } $hwmon = trim(file_get_contents(HWMON_PATH . '/hwmon' . $match[2] . '/name')); $fan = $match[3]; $pwm = preg_replace('~fan(\d+)~', 'pwm$1', $fan); $name = $hwmon . '/' . $fan; $inputs[$name] = [ 'input' => $input, 'pwm' => preg_replace('~fan(\d+)_input~', 'pwm$1', $input), 'hwmon' => 'hwmon' . $match[2], 'name' => $name, 'type' => 'hwmon', 'options' => [ 'hwmon' => $hwmon, 'fan' => $fan, 'pwm' => $pwm, ], ]; return $inputs; }, []); $unknownInputs = []; foreach ($inputs as $name => $input) { [$min, $max] = $this->testPwm($input['pwm'], $input['input']); if ($max === 0 || $min > $max*0.4) { $unknownInputs[$name] = $input; continue; } $this->info(sprintf('%s at full speed: %d; stopped: %d', $name, $max, $min)); $fans[] = $input; } if (count($unknownInputs) > 0) { $this->info('Some fans could not be assigned to a pwm. Trying remaining pwms...'); $assignedPwms = array_map(fn($fan) => $fan['pwm'], $fans); $pwms = array_reduce(glob(HWMON_PATH . '/hwmon*/pwm*'), function ($pwms, $pwm) use ($assignedPwms) { if (!preg_match('~(hwmon(\d+)/pwm(\d+))$~', $pwm, $match) || in_array($pwm, $assignedPwms)) { return $pwms; } $hwmon = $match[2]; if (!isset($pwms[$hwmon])) { $pwms[$hwmon] = []; } $pwms[$hwmon][] = $pwm; return $pwms; }, []); foreach ($unknownInputs as $id => $input) { if (!isset($pwms[$input['hwmon']])) { continue; } foreach ($pwms[$input['hwmon']] as $pwm) { if ($input['pwm'] !== $pwm) { continue; } [$min, $max] = $this->testPwm($pwm, $input['input']); if ($max === 0 || $min > $max*0.4) { continue; } $input['pwm'] = $pwm; $input['options']['pwm'] = basename($pwm); $fans[] = $input; continue 2; } $this->info($id . ' not connected or not controllable'); } } return array_map(function ($fan) { unset($fan['input'], $fan['pwm']); return $fan; }, $fans); } protected function testPwm($pwm, $input): array { $currentEnable = file_get_contents($pwm . '_enable'); file_put_contents($pwm . '_enable', '1'); file_put_contents($pwm, '255'); sleep(4); $fullSpeed = (int)file_get_contents($input); if ($fullSpeed === 0) { file_put_contents($pwm . '_enable', $currentEnable); return [0, 0]; } file_put_contents($pwm, '0'); sleep(10); $stopSpeed = (int)file_get_contents($input); file_put_contents($pwm . '_enable', $currentEnable); return [$stopSpeed, $fullSpeed]; } }