<?php namespace App\Subroutines; use App\Application; use App\Concerns\InteractiveConsole; use App\Model\Fan\HwmonFan; use App\Service\Utils; use Hugga\Console; use Hugga\Input\Question\Choice; use Hugga\Input\Question\Confirmation; class InitializeConfig { use InteractiveConsole; /** @var Application */ protected $app; /** * @param Application $app */ public function __construct(Application $app, Console $console) { $this->app = $app; $this->console = $console; } public function main(): int { $fanConfig = $this->app->fanConfig; $this->info('No fans configured. Detecting fans...'); $fans = $this->detectControllableFans(); if (count($fans) > 0) { foreach ($fans as $fan) { $this->line(''); $this->info('Fan ' . $fan->name); $start = $this->detectStartValue($fan); $fan->setStartValue($start); do { $answer = $this->ask(new Choice([ 'name fan', 'adjust start value', 'define limit', 'add fan', 'skip fan', ], 'What next?', 'name fan')); switch ($answer) { case 'adjust start value': do { $fan->setPwm(0); $startValue = $this->ask('What value to try?', $start); $fan->setPwm($startValue); } while (!$this->ask(new Confirmation('Use that value?'))); $fan->resetState(); $fan->setStartValue($startValue); break; case 'define limit': do { $fan->setPwm(255); $maxValue = $this->ask('What value to try?', 255); $fan->setPwm($maxValue); Utils::waitForStableRpm($fan); $this->line('fan runs at ' . $fan->getCurrentSpeed() . ' rpm now'); } while (!$this->ask(new Confirmation('Use that value?'))); $fan->resetState(); $fan->setMaxValue($maxValue); break; case 'name fan': $name = $this->ask('Name of the fan: ', $fan->name); $fan->name = $name; break; case 'add fan': $fanConfig->addFan($fan); break 2; case 'skip fan': break 2; default: $this->warn('not implemented'); break; } } while (true); } $fanConfig->save(); return 0; } $this->error('We could not find any fan to control.'); return 1; } /** * @return array|HwmonFan[] */ 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; if (!file_exists(HWMON_PATH . '/hwmon' . $match[2] . '/' . $pwm)) { return $inputs; } $options = [ 'hwmon' => $hwmon, 'fan' => $fan, 'pwm' => $pwm, ]; $inputs[$name] = [ 'fan' => new HwmonFan($name, $options), 'options' => $options, 'hwmon' => 'hwmon' . $match[2], ]; return $inputs; }, []); $unknownInputs = []; foreach ($inputs as $name => $input) { [$min, $max] = $this->testPwm($input['fan']); if ($max === 0 || $min > $max*0.4) { $unknownInputs[$name] = $input; continue; } $this->line(sprintf('%s at full speed: %d; stopped: %d', $name, $max, $min)); $fans[] = $input['fan']; } if (count($unknownInputs) > 0) { $this->info(PHP_EOL . 'Some fans could not be assigned to a pwm. Trying remaining pwms...'); $assignedPwms = array_map(fn(HwmonFan $fan) => $fan->toArray()['options']['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(basename($pwm), $assignedPwms)) { return $pwms; } $hwmon = $match[2]; if (!isset($pwms[$hwmon])) { $pwms[$hwmon] = []; } $pwms[$hwmon][] = basename($pwm); return $pwms; }, []); foreach ($unknownInputs as $id => $input) { if (!isset($pwms[$input['hwmon']])) { continue; } foreach ($pwms[$input['hwmon']] as $pwm) { $name = $input['fan']->name; $options = $input['options']; if ($options['pwm'] === $pwm) { continue; } $options['pwm'] = $pwm; $fan = new HwmonFan($name, $options); [$min, $max] = $this->testPwm($fan); if ($max === 0 || $min > $max*0.4) { continue; } $fans[] = $fan; continue 2; } $this->info($id . ' not connected or not controllable'); } } return $fans; } protected function testPwm(HwmonFan $fan): array { $fan->setPwm(255); Utils::waitForStableRpm($fan); $fullSpeed = $fan->getCurrentSpeed(); if ($fullSpeed === 0) { $fan->resetState(); return [0, 0]; } $fan->setPwm(0); Utils::waitForStableRpm($fan); $stopSpeed = $fan->getCurrentSpeed(); $fan->resetState(); return [$stopSpeed, $fullSpeed]; } protected function detectStartValue(HwmonFan $fan): int { $this->info('Detecting start value for ' . $fan->name); $fan->setPwm(0); Utils::waitForStableRpm($fan); $minSpeed = $fan->getCurrentSpeed() * 1.1; $pwm = 0; do { $fan->setPwm($pwm += 5); Utils::waitForStableRpm($fan); $currentSpeed = $fan->getCurrentSpeed(); $this->line(sprintf('%d rpm with pwm value %d', $currentSpeed, $pwm)); } while ($minSpeed >= $currentSpeed); $fan->resetState(); return $pwm; } }