import os
[docs]class LEDError(IOError):
"""Base class for LED errors."""
pass
[docs]class LED(object):
def __init__(self, name, brightness=None):
"""Instantiate an LED object and open the sysfs LED corresponding to
the specified name.
`brightness` can be a boolean for on/off, integer value for a specific
brightness, or None to preserve existing brightness. Default is
preserve existing brightness.
Args:
name (str): Linux led name.
brightness (bool, int, None): Initial brightness.
Returns:
LED: LED object.
Raises:
LEDError: if an I/O or OS error occurs.
TypeError: if `name` or `brightness` types are invalid.
ValueError: if `brightness` value is invalid.
"""
self._fd = None
self._name = None
self._max_brightness = None
self._open(name, brightness)
def __del__(self):
self.close()
def __enter__(self):
pass
def __exit__(self, t, value, traceback):
self.close()
def _open(self, name, brightness):
if not isinstance(name, str):
raise TypeError("Invalid name type, should be string.")
if not isinstance(brightness, (bool, int, type(None))):
raise TypeError("Invalid brightness type, should be bool, int, or None.")
led_path = "/sys/class/leds/%s" % name
if not os.path.isdir(led_path):
raise ValueError("LED %s not found!" % name)
# Read max brightness
try:
with open("/sys/class/leds/%s/max_brightness" % name, "r") as f_max_brightness:
max_brightness = int(f_max_brightness.read())
except IOError as e:
raise LEDError(e.errno, "Reading LED max brightness: " + e.strerror)
# Open brightness
try:
self._fd = os.open("/sys/class/leds/%s/brightness" % name, os.O_RDWR)
except OSError as e:
raise LEDError(e.errno, "Opening LED brightness: " + e.strerror)
self._max_brightness = max_brightness
self._name = name
# Set initial brightness
if brightness:
self.write(brightness)
# Methods
[docs] def read(self):
"""Read the brightness of the LED.
Returns:
int: Current brightness.
Raises:
LEDError: if an I/O or OS error occurs.
"""
# Read value
try:
buf = os.read(self._fd, 8)
except OSError as e:
raise LEDError(e.errno, "Reading LED brightness: " + e.strerror)
# Rewind
try:
os.lseek(self._fd, 0, os.SEEK_SET)
except OSError as e:
raise LEDError(e.errno, "Rewinding LED brightness: " + e.strerror)
return int(buf)
[docs] def write(self, brightness):
"""Set the brightness of the LED to `brightness`.
`brightness` can be a boolean for on/off, or integer value for a
specific brightness.
Args:
brightness (bool, int): Brightness value to set.
Raises:
LEDError: if an I/O or OS error occurs.
TypeError: if `brightness` type is not bool or int.
"""
if not isinstance(brightness, (bool, int)):
raise TypeError("Invalid brightness type, should be bool or int.")
if isinstance(brightness, bool):
brightness = self._max_brightness if brightness else 0
else:
if not 0 <= brightness <= self._max_brightness:
raise ValueError("Invalid brightness value, should be between 0 and %d." % self._max_brightness)
# Write value
try:
os.write(self._fd, b"%d\n" % brightness)
except OSError as e:
raise LEDError(e.errno, "Writing LED brightness: " + e.strerror)
# Rewind
try:
os.lseek(self._fd, 0, os.SEEK_SET)
except OSError as e:
raise LEDError(e.errno, "Rewinding LED brightness: " + e.strerror)
[docs] def close(self):
"""Close the sysfs LED.
Raises:
LEDError: if an I/O or OS error occurs.
"""
if self._fd is None:
return
try:
os.close(self._fd)
except OSError as e:
raise LEDError(e.errno, "Closing LED: " + e.strerror)
self._fd = None
# Immutable properties
@property
def fd(self):
"""Get the file descriptor for the underlying sysfs LED "brightness"
file of the LED object.
:type: int
"""
return self._fd
@property
def name(self):
"""Get the sysfs LED name.
:type: str
"""
return self._name
@property
def max_brightness(self):
"""Get the LED's max brightness.
:type: int
"""
return self._max_brightness
# Mutable properties
def _get_brightness(self):
# Read brightness
return self.read()
def _set_brightness(self, brightness):
return self.write(brightness)
brightness = property(_get_brightness, _set_brightness)
"""Get or set the LED's brightness.
Value can be a boolean for on/off, or integer value a for specific
brightness.
Raises:
LEDError: if an I/O or OS error occurs.
TypeError: if `brightness` type is not bool or int.
ValueError: if `brightness` value is invalid.
:type: int
"""
# String representation
def __str__(self):
return "LED %s (fd=%d, max_brightness=%d)" % (self._name, self._fd, self._max_brightness)