Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 57 additions & 2 deletions rpi_backlight/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ class BoardType(Enum):


_BACKLIGHT_SYSFS_PATHS = {
BoardType.RASPBERRY_PI: next(iglob("/sys/class/backlight/*-0045/"), "/sys/class/backlight/rpi_backlight/"),
BoardType.RASPBERRY_PI: next(
iglob("/sys/class/backlight/*-0045/"), "/sys/class/backlight/rpi_backlight/"
),
BoardType.TINKER_BOARD: "/sys/devices/platform/ff150000.i2c/i2c-3/3-0045/",
BoardType.TINKER_BOARD_2: "/sys/devices/platform/ff3e0000.i2c/i2c-8/8-0045/",
BoardType.GENERIC: "/sys/class/backlight/backlight/",
Expand All @@ -38,6 +40,56 @@ class BoardType(Enum):
_EMULATOR_MAGIC_STRING = ":emulator:"


def _detect_working_rpi_backlight_sysfs_path() -> Path:
"""
Pick a working backlight device on systems that expose multiple
/sys/class/backlight/* entries (e.g. Pi 5 + KMS/DSI).
We probe by writing the current brightness value back to 'brightness'.
"""
base = Path("/sys/class/backlight")
if not base.exists():
return Path("/sys/class/backlight/rpi_backlight/")

try:
candidates = sorted(p for p in base.iterdir() if p.is_dir())
except OSError:
return Path(
next(
iglob("/sys/class/backlight/*-0045/"),
"/sys/class/backlight/rpi_backlight/",
)
)

def _read_int(path: Path):
try:
return int(path.read_text())
except Exception:
return None

for p in candidates:
brightness = p / "brightness"
if not brightness.exists():
continue

current = _read_int(p / "actual_brightness")
if current is None:
current = _read_int(brightness)
if current is None:
continue

try:
brightness.write_text(str(current))
return p
except OSError as e:
if e.errno in (errno.EINVAL, errno.EIO, getattr(errno, "EREMOTEIO", 121)):
continue
if e.errno == errno.EPERM:
raise
continue

return Path("/sys/class/backlight/rpi_backlight/")


def _permission_denied() -> None:
raise PermissionError(
"You must either run this program as root or change the permissions "
Expand All @@ -60,7 +112,10 @@ def __init__(
)

if not backlight_sysfs_path:
backlight_sysfs_path = _BACKLIGHT_SYSFS_PATHS[board_type]
if board_type == BoardType.RASPBERRY_PI:
backlight_sysfs_path = str(_detect_working_rpi_backlight_sysfs_path())
else:
backlight_sysfs_path = _BACKLIGHT_SYSFS_PATHS[board_type]
elif backlight_sysfs_path == _EMULATOR_MAGIC_STRING:
if not _EMULATOR_SYSFS_TMP_FILE_PATH.exists():
raise RuntimeError(
Expand Down
22 changes: 22 additions & 0 deletions rpi_backlight/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ def main():
parser = _create_argument_parser()
args = parser.parse_args()

if args.sysfs_path in ("on", "off"):
parser.error(
"invalid SYSFS_PATH. Use -p on/off (or -p toggle) instead of 'rpi-backlight on|off'."
)

backlight = Backlight(
board_type=STRING_TO_BOARD_TYPE[args.board_type],
backlight_sysfs_path=args.sysfs_path,
Expand All @@ -102,8 +107,12 @@ def main():
"-b/--set-brightness must be used without other options except for -d/--duration"
)
# backlight.fade context manager can be used always as args.fade defaults to zero
if (backlight.power is False) and (args.set_brightness > 0):
backlight.power = True
with backlight.fade(duration=args.duration):
backlight.brightness = args.set_brightness
if (backlight.power is True) and (args.set_brightness == 0):
backlight.power = False
return

if args.set_power:
Expand All @@ -122,6 +131,19 @@ def main():
backlight.power = True
with backlight.fade(duration=args.duration):
backlight.brightness = 100
elif args.set_power == "on":
# Ensure brightness is 0 when we turn the display on
backlight.brightness = 0
if args.board_type == "raspberry-pi":
backlight.power = True
with backlight.fade(duration=args.duration):
backlight.brightness = 100
elif args.set_power == "off":
if backlight.power:
with backlight.fade(duration=args.duration):
backlight.brightness = 0
if args.board_type == "raspberry-pi":
backlight.power = False
else:
backlight.power = True if args.set_power == "on" else False
return
Expand Down
Loading