Skip to content
Snippets Groups Projects
FanConfig.php 5.68 KiB
Newer Older
Thomas Flori's avatar
Thomas Flori committed
<?php

namespace App;

Thomas Flori's avatar
Thomas Flori committed
use App\Model\Fan;
use App\Model\Rule;
use App\Model\Sensor;
use Hugga\Console;
use Hugga\Output\Drawing\Table;

Thomas Flori's avatar
Thomas Flori committed
class FanConfig
{
    protected $path = '/dev/null';
Thomas Flori's avatar
Thomas Flori committed

    protected $loaded = false;

    /** @var array|Fan[] */
Thomas Flori's avatar
Thomas Flori committed
    protected $fans = [];

Thomas Flori's avatar
Thomas Flori committed
    /** @var array|Sensor[] */
    protected $sensors = [];

    /** @var array|Rule[] */
    protected $rules = [];

    public function __construct(string $path)
    {
        $this->path = $path;
    }

Thomas Flori's avatar
Thomas Flori committed
    public function hasFans(): bool
    {
Thomas Flori's avatar
Thomas Flori committed
        $this->load();
Thomas Flori's avatar
Thomas Flori committed
        return count($this->fans) > 0;
    }

Thomas Flori's avatar
Thomas Flori committed
    public function addFan(Fan $fan): self
Thomas Flori's avatar
Thomas Flori committed
    {
Thomas Flori's avatar
Thomas Flori committed
        $this->load();
        $this->fans[$fan->name] = $fan;
Thomas Flori's avatar
Thomas Flori committed
        return $this;
    }

Thomas Flori's avatar
Thomas Flori committed
    /** @return Fan[]|array */
    public function getFans(): array
    {
        $this->load();
        return $this->fans;
    }

Thomas Flori's avatar
Thomas Flori committed
    public function getSensors(): array
    {
        $this->load();
        return $this->sensors;
    }

    public function getRules(): array
    {
        $this->load();
        return $this->rules;
    }

Thomas Flori's avatar
Thomas Flori committed
    protected function load()
Thomas Flori's avatar
Thomas Flori committed
    {
Thomas Flori's avatar
Thomas Flori committed
        if (!$this->loaded) {
            $this->readConfig();
Thomas Flori's avatar
Thomas Flori committed
        }
Thomas Flori's avatar
Thomas Flori committed
    }
Thomas Flori's avatar
Thomas Flori committed

Thomas Flori's avatar
Thomas Flori committed
    public function readConfig(): self
    {
        if (!file_exists($this->path)) {
            return $this;
        }

        $this->loaded = true;
        $cfg = include($this->path);
Thomas Flori's avatar
Thomas Flori committed

        // validate config
        if (!is_array($cfg)) {
            throw new \InvalidArgumentException('given configuration is not a fan-ctrl config');
        }

Thomas Flori's avatar
Thomas Flori committed
        foreach ($cfg['fans'] ?? [] as $fanCfg) {
            $class = $fanCfg['type'];
            $fan = new $class($fanCfg['name'], $fanCfg['options']);
            $this->fans[$fan->name] = $fan;
        }

        foreach ($cfg['sensors'] ?? [] as $sensorCfg) {
            $class = $sensorCfg['type'];
            $sensor = new $class($sensorCfg['name'], $sensorCfg['options']);
            $this->sensors[$sensor->name] = $sensor;
        }

        foreach ($cfg['rules'] ?? [] as $ruleCfg) {
            $class = $ruleCfg['type'];
            $fans = array_map(fn($name) => $this->fans[$name] ?? null, $ruleCfg['fans']);
            if (in_array(null, $fans, true)) {
                continue;
            }
            $sensor = $this->sensors[$ruleCfg['sensor']] ?? null;
            if (!$sensor) {
                continue;
            }
            $rule = new $class($fans, $sensor, $ruleCfg['options']);
            $this->rules[] = $rule;
        }

        return $this;
Thomas Flori's avatar
Thomas Flori committed
    }

    public function save()
    {
        $code = '<?php' . PHP_EOL . PHP_EOL .
            'return ' . $this->exportArray([
Thomas Flori's avatar
Thomas Flori committed
                'fans' => array_map(function (Fan $fan) {
                    return $fan->toArray();
                }, array_values($this->fans)),
                'sensors' => array_map(function (Sensor $sensor) {
                    return $sensor->toArray();
                }, array_values($this->sensors)),
                'rules' => array_map(function (Rule $rule) {
                    return $rule->toArray();
                }, $this->rules),
Thomas Flori's avatar
Thomas Flori committed
            ]) . ';' . PHP_EOL;
        file_put_contents($this->path, $code);
    }

    protected function exportArray(array $array, $indentation = 0)
    {
        $indexed = array_keys($array) === array_keys(array_keys($array));
        $indentation += 4;
        $var = '[' . PHP_EOL;
        foreach ($array as $key => $value) {
            $var .= str_repeat(' ', $indentation);
            if (!$indexed) {
                $var .= var_export($key, true) . ' => ';
            }
            $var .= is_array($value) ? $this->exportArray($value, $indentation) : var_export($value, true);
            $var .= ',' . PHP_EOL;
        }
        $indentation -= 4;
        $var .= str_repeat(' ', $indentation) . ']';
        return $var;
    }
Thomas Flori's avatar
Thomas Flori committed

    public function display(Console $console)
    {
        $this->load();

        $console->info('Fans');
        $table = new Table($console, array_map(function (Fan $fan) {
            if ($fan instanceof Fan\HwmonFan) {
                return $fan->toRow();
Thomas Flori's avatar
Thomas Flori committed
            }

            return [
                $fan->name,
                null,
                null,
                null,
                null,
            ];
        }, $this->fans), ['Name', 'hwmon', 'Fan', 'PWM', 'start', 'max']);
        $table->column(4, ['width' => 5]);
        $table->draw();

Thomas Flori's avatar
Thomas Flori committed
        if (!empty($this->sensors)) {
            $console->line('');

            $console->info('Sensors');
            $table = new Table($console, array_map(function (Sensor $sensor) {
                $options = $sensor->toArray()['options'];
                $result = [$sensor->name];
                if ($sensor instanceof Sensor\HwmonSensor) {
                    $result[] = $options['hwmon'];
                    $result[] = $options['temp'];
                } elseif ($sensor instanceof Sensor\CommandSensor) {
                    $result[] = null;
                    $result[] = $options['command'];
                } else {
                    $result[] = null;
                    $result[] = null;
                }
                return $result;
            }, $this->sensors), ['Name', 'hwmon', 'sensor / command']);
            $table->draw();
        }
Thomas Flori's avatar
Thomas Flori committed
        if (!empty($this->rules)) {
            $console->line('');
Thomas Flori's avatar
Thomas Flori committed
            $console->info('Rules');
            $table = new Table($console, array_map(function (Rule $rule) {
                return [
                    implode(', ', array_map(fn($fan) => $fan->name, $rule->fans)),
                    $rule->sensor->name,
                    $rule->describe(),
                ];
            }, $this->rules), ['Fans', 'Sensor', 'Description']);
            $table->draw();
        }
Thomas Flori's avatar
Thomas Flori committed
    }
Thomas Flori's avatar
Thomas Flori committed
}