dept-of-scrapyard-robotics / pwm-fan-control
A Laravel package for controlling PWM-controlled fans.
Installs: 2
Dependents: 1
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/dept-of-scrapyard-robotics/pwm-fan-control
Requires
- php: ^8.3
- ext-pwm: *
Requires (Dev)
- mockery/mockery: ^1.6
- pestphp/pest: ^4.1
README
A modern PHP 8.3+ library for controlling PWM-driven fans on embedded Linux devices. This package provides an elegant, object-oriented API with fluent method chaining, smooth ramping, temperature-based control, and coordinated effects.
Features
- Object-Oriented API: Clean, fluent interface for fan control
- Speed Control: Precise percentage-based speed control (0-100%)
- Smooth Effects: Ramping, pulsing, and custom speed curves
- Temperature Control: Automatic fan speed adjustment based on CPU temperature
- Speed Presets: Convenient named speed levels (low, medium, high, full)
- Type-Safe: Full PHP 8.3+ type hints and return type declarations
- Chainable Methods: Fluent API for readable, expressive code
- Comprehensive Testing: Full Pest v4 test suite included
Requirements
- PHP 8.3 or higher
- php-pwm extension installed
- Embedded Linux device with PWM support (Jetson Orin Nano, Raspberry Pi, etc.)
- PWM device nodes exported (e.g.,
/sys/class/pwm/pwmchip3/pwm0
)
Installation
Install via Composer
composer require dept-of-scrapyard-robotics/pwm-fan-control
Install php-pwm Extension
Before using this library, you must install the php-pwm extension on your embedded Linux device. See the php-pwm extension installation guide for complete instructions.
Export PWM Device
Before first use, export the PWM device:
# Export PWM channel 0 on chip 3 echo 0 | sudo tee /sys/class/pwm/pwmchip3/export # This creates /sys/class/pwm/pwmchip3/pwm0/
Core Concepts
PWMFan
A PWMFan
is an object-oriented wrapper around the php-pwm extension's Pwm
class. It represents a single controllable fan connected to a specific PWM device path.
Basic Usage
use DeptOfScrapyardRobotics\PWM\Fans\PWMFan; // Create a fan controller $fan = new PWMFan('/sys/class/pwm/pwmchip3/pwm0'); // Set fan speed to 50% $fan->setSpeed(50.0); // Turn on at last known speed $fan->on(); // Turn off $fan->off(); // Check status echo "Speed: " . $fan->getSpeed() . "%\n"; echo "Running: " . ($fan->isRunning() ? 'Yes' : 'No') . "\n";
API Reference
Construction
public function __construct(string $pwm_device_path, int $frequency = 1000)
Creates a new PWMFan instance for the specified PWM device.
- Parameters:
$pwm_device_path
- Path to PWM device (e.g.,/sys/class/pwm/pwmchip3/pwm0
)$frequency
- PWM frequency in Hz (default: 1000)
Example:
$fan = new PWMFan('/sys/class/pwm/pwmchip3/pwm0', 1000);
Core Operations
on()
public function on(): static
Turn the fan on at the last known speed (default 50%).
$fan->on();
off()
public function off(): static
Turn the fan off (disable PWM output).
$fan->off();
setSpeed()
public function setSpeed(float $percent): static
Set the fan speed as a percentage.
- Parameters:
$percent
- Speed percentage (0.0 - 100.0)
- Returns:
$this
for method chaining - Throws:
InvalidArgumentException
if speed is out of range
$fan->setSpeed(75.0); // Set to 75%
getSpeed()
public function getSpeed(): float
Get the current fan speed percentage.
$speed = $fan->getSpeed(); // Returns 0.0 - 100.0
isRunning()
public function isRunning(): bool
Check if the fan is currently running.
if ($fan->isRunning()) { echo "Fan is on\n"; }
getStatus()
public function getStatus(): array
Get detailed fan status information.
- Returns: Array with keys:
enabled
(bool)speed
(float) - Current speed percentagelastSpeed
(float) - Last known speedfrequency
(int) - PWM frequency in HzdutyCycle
(float) - Duty cycle percentagedevicePath
(string) - PWM device path
$status = $fan->getStatus(); echo "Speed: {$status['speed']}%\n"; echo "Frequency: {$status['frequency']} Hz\n";
Speed Presets
setPreset()
public function setPreset(string $preset): static
Set fan speed using named presets.
- Parameters:
$preset
- Preset name (case-insensitive):'off'
,'low'
,'medium'
,'high'
,'full'
- Preset Speeds:
'off'
- 0%'low'
- 25%'medium'
- 50%'high'
- 75%'full'
- 100%
$fan->setPreset('low'); // 25% $fan->setPreset('HIGH'); // 75% (case-insensitive) $fan->setPreset('full'); // 100%
Effects & Animations
rampUp()
public function rampUp(float $targetSpeed = 100.0, int $duration_ms = 2000, int $steps = 20): static
Gradually increase fan speed from current speed to target speed.
- Parameters:
$targetSpeed
- Target speed percentage (0.0 - 100.0)$duration_ms
- Duration in milliseconds$steps
- Number of intermediate steps
// Ramp from current speed to 100% over 3 seconds $fan->rampUp(100.0, 3000, 30);
rampDown()
public function rampDown(float $targetSpeed = 0.0, int $duration_ms = 2000, int $steps = 20): static
Gradually decrease fan speed to target speed.
// Ramp down to 25% over 2 seconds $fan->rampDown(25.0, 2000, 20);
pulse()
public function pulse(float $lowSpeed = 30.0, float $highSpeed = 80.0, int $cycles = 3, int $duration_ms = 2000): static
Create a pulsing effect by ramping between two speeds.
- Parameters:
$lowSpeed
- Low speed percentage$highSpeed
- High speed percentage$cycles
- Number of pulse cycles$duration_ms
- Duration per cycle
// Pulse between 30% and 80% three times $fan->pulse(30.0, 80.0, 3, 2000);
Temperature Control
autoControl()
public function autoControl(float $currentTemp, float $minTemp = 40.0, float $maxTemp = 80.0, float $minSpeed = 25.0): static
Automatically adjust fan speed based on temperature.
- Parameters:
$currentTemp
- Current temperature in Celsius$minTemp
- Minimum temperature (fan off below this)$maxTemp
- Maximum temperature (fan at 100% above this)$minSpeed
- Minimum fan speed when active
Behavior:
- Temperature ≤
$minTemp
: Fan off - Temperature ≥
$maxTemp
: Fan at 100% - Between: Linear interpolation from
$minSpeed
to 100%
$temp = $fan->getCPUTemp(); $fan->autoControl($temp, 40.0, 80.0, 25.0);
getCPUTemp()
public function getCPUTemp(int $zone = 0): float
Read CPU temperature from thermal zone.
- Parameters:
$zone
- Thermal zone number (default: 0)
- Returns: Temperature in Celsius
$temp = $fan->getCPUTemp(0); // Read from thermal_zone0 echo "CPU Temperature: {$temp}°C\n";
Usage Examples
Example 1: Basic Speed Control
use DeptOfScrapyardRobotics\PWM\Fans\PWMFan; $fan = new PWMFan('/sys/class/pwm/pwmchip3/pwm0'); // Set various speeds $fan->setSpeed(25.0); // 25% sleep(2); $fan->setSpeed(50.0); // 50% sleep(2); $fan->setSpeed(100.0); // 100% sleep(2); // Turn off $fan->off();
Example 2: Temperature-Based Control
use DeptOfScrapyardRobotics\PWM\Fans\PWMFan; $fan = new PWMFan('/sys/class/pwm/pwmchip3/pwm0'); // Monitor and adjust fan speed based on temperature while (true) { $temp = $fan->getCPUTemp(); $fan->autoControl($temp, 40.0, 80.0, 25.0); echo "Temp: {$temp}°C, Fan: {$fan->getSpeed()}%\n"; sleep(2); }
Example 3: Smooth Ramping Effect
use DeptOfScrapyardRobotics\PWM\Fans\PWMFan; $fan = new PWMFan('/sys/class/pwm/pwmchip3/pwm0'); // Smooth startup $fan->rampUp(100.0, 3000, 30); // Ramp to 100% over 3 seconds sleep(5); // Smooth shutdown $fan->rampDown(0.0, 3000, 30); // Ramp to 0% over 3 seconds
Example 4: Pulsing Effect
use DeptOfScrapyardRobotics\PWM\Fans\PWMFan; $fan = new PWMFan('/sys/class/pwm/pwmchip3/pwm0'); // Create breathing effect $fan->pulse(30.0, 80.0, 5, 2000); // 5 pulses, 2s each
Example 5: Speed Presets
use DeptOfScrapyardRobotics\PWM\Fans\PWMFan; $fan = new PWMFan('/sys/class/pwm/pwmchip3/pwm0'); $fan->setPreset('low'); // 25% sleep(2); $fan->setPreset('medium'); // 50% sleep(2); $fan->setPreset('high'); // 75% sleep(2); $fan->setPreset('full'); // 100% sleep(2); $fan->setPreset('off'); // 0%
Testing
The library includes a comprehensive Pest v4 test suite covering unit tests and integration tests.
Running Tests
# Run all tests composer test # Run tests quietly composer test:quiet # Run with coverage report composer test:coverage # Run specific test file ./vendor/bin/pest tests/Unit/PWMFanTest.php
Test Structure
tests/
├── Pest.php # Test configuration
└── Unit/
└── PWMFanTest.php # PWMFan unit tests
Included Examples
The package includes three comprehensive examples:
Running Examples
# Example 1: Basic usage sudo php examples/01_basic_usage.php # Example 2: Temperature-based control sudo php examples/02_temperature_control.php # Example 3: Advanced effects sudo php examples/03_advanced_effects.php
Example Overview
01_basic_usage.php
- Basic on/off control
- Speed control and adjustment
- Speed presets
- Status information
02_temperature_control.php
- Reading CPU temperature
- Automatic speed adjustment
- Temperature monitoring loop
- Custom temperature scenarios
03_advanced_effects.php
- Smooth ramping (up and down)
- Pulsing effects
- Custom speed curves
- Coordinated effect sequences
Troubleshooting
Extension Not Found
PHP Fatal error: Uncaught Error: Class 'Pwm\Pwm' not found
Solution: Install the php-pwm extension first.
PWM Device Not Found
RuntimeException: Device path does not exist
Solution:
- Export the PWM device:
echo 0 | sudo tee /sys/class/pwm/pwmchip3/export
- Verify device exists:
ls /sys/class/pwm/pwmchip3/pwm0
- Ensure proper permissions (add user to
gpio
group)
Permission Denied
RuntimeException: Failed to write to file
Solution: Run with sudo
or configure udev rules:
# /etc/udev/rules.d/99-pwm.rules SUBSYSTEM=="pwm", KERNEL=="pwmchip*", ACTION=="add", RUN+="/bin/chgrp -R gpio /sys%p", RUN+="/bin/chmod -R g+w /sys%p" # Reload rules sudo udevadm control --reload-rules sudo udevadm trigger
Thermal Zone Not Found
RuntimeException: Thermal zone 0 not found
Solution:
- Check available zones:
ls /sys/class/thermal/
- Use correct zone number:
$fan->getCPUTemp(1)
forthermal_zone1
License
MIT License. See LICENSE file for details.
Credits
This library wraps the php-pwm extension, which provides low-level PWM hardware control via Linux sysfs.
Contributing
Contributions are welcome! When contributing:
- Follow PSR-12 coding standards
- Add tests for new features
- Update documentation as needed
- Ensure all tests pass before submitting pull requests
Support
For issues related to:
- This library: Open an issue in this repository
- php-pwm extension: See the php-pwm repository
- Hardware setup: Consult your device's PWM configuration documentation