SunReactor is a lightweight, headless Rust daemon designed to automate monitor hardware brightness. By calculating solar elevation based on your exact geolocation and time, it generates a brightness curve that adapts to seasonal daylight shifts. Combined with real-time cloudiness data from the OpenWeather API and customizable limits via a dedicated TUI, the daemon manages your displays in the background.
A fixed clock schedule (like dimming the screen exactly at 8:00 PM) falls out of sync because daylight hours shift between seasons in many regions. SunReactor uses the sun's elevation above the horizon to calculate brightness change.
☀ (Solar Noon) --> Max Brightness
/ \
/ \ (Smoothly dimming via gamma curve)
/ \
- 0° (Horizon) ------------------------------
\
\ ☾ (Night) --> Min Brightness
1. Smoothstep:
t = (Elevation - NightFloor) / (DayPeak - NightFloor)
2. Gamma Curve:curve = t^γ
3. Projection:Brightness = Min% + (Max% - Min%) * curve * weather_multiplier
-
Local by Default: SunReactor does all the daylight math locally. Basically, it generates an adaptive brightness curve based on your selected city’s sunrise/sunset times for the current date. Since that is deterministic, it can work completely offline, with the sole exception of the optional weather integration.
-
Multi-Monitor Support: 50% brightness on an IPS panel looks different than 50% on a VA or OLED. You can set distinct minimum, maximum, gamma curvature, and gain values for each display. The daemon calculates each monitor's brightness independently.
SunReactor is built to be predictable and stay out of the way:
- Hardware Control: Adjusts the actual backlight via
ddcutil(external) andsysfs/brightnessctl(internal). - Synchronous: No async runtime. It executes a simple synchronous loop: wake, compute, write to hardware, sleep..
- Unprivileged: Runs as a systemd user service. No root access or dbus required.
- Idle Sync: Includes its own automatic screen dimming feature by integrating directly with Wayland/X11 idle protocols. This allows you to turn off native DE power management to prevent conflicting brightness states, ensuring displays wake up directly to the latest solar calculation rather than a cached value.
- Optional Weather: If you provide a free OpenWeather API key, the daemon reads cloud cover and slightly dims your displays on overcast days. This acts only as a multiplier over the base calculation. Additionally, the TUI provides a view of current weather conditions.
SunReactor relies on the following tools being installed on your system to control hardware brightness:
- For External Monitors (DDC/CI): Ensure
ddcutilis installed.- Arch:
sudo pacman -S ddcutil - Fedora:
sudo dnf install ddcutil - Ubuntu/Debian:
sudo apt install ddcutil
- Arch:
- For Laptop Panels: Ensure
brightnessctlis installed.- Arch:
sudo pacman -S brightnessctl - Fedora:
sudo dnf install brightnessctl - Ubuntu/Debian:
sudo apt install brightnessctl
- Arch:
Note
Do not add every user to i2c or video by default. Run sunreactorctl doctor
after installation. It tests actual device access and distinguishes active
access, stale login sessions, and permission failures.
The installer downloads the checksum-verified x86-64 GNU/Linux artifact built on Ubuntu 22.04, smoke-tests it before replacing anything, and verifies the user unit, config, daemon startup, doctor result, and IPC. It never installs Rust or changes system groups. Failed upgrades restore the previous binaries and unit.
curl -sL https://raw.githubusercontent.com/arcanorca/SunReactor/main/install.sh | bashWhen run from a terminal, the installer detects and configures viable monitors, then opens the TUI after a three-second countdown.
The installer writes to ~/.local/bin and does not require sudo. If no compatible
artifact exists, it leaves the installation unchanged and prints separate source-build
instructions.
View Manual Installation Steps
- Download the latest x86-64 GNU/Linux archive and matching
.sha256from Releases, then verify it:
sha256sum -c sunreactor-VERSION-linux-x86_64-gnu.tar.gz.sha256
tar xzf sunreactor-VERSION-linux-x86_64-gnu.tar.gz
./sunreactorctl --version
./sunreactord --help- Move the binaries to your local PATH:
mkdir -p ~/.local/bin
install -m 755 sunreactord sunreactorctl ~/.local/bin/- Render both service paths from the same install directory and start the daemon:
mkdir -p ~/.config/systemd/user
sed "s|@BINDIR@|$HOME/.local/bin|g" sunreactord.service > ~/.config/systemd/user/sunreactord.service
systemd-analyze --user verify ~/.config/systemd/user/sunreactord.service
systemctl --user daemon-reload
systemctl --user enable --now sunreactord.serviceIf you have Rust installed, you can build from source:
git clone https://github.com/arcanorca/SunReactor.git
cd SunReactor
# Build and install explicitly to ~/.cargo/bin
cargo build --release --locked
install -Dm755 target/release/sunreactord ~/.cargo/bin/sunreactord
install -Dm755 target/release/sunreactorctl ~/.cargo/bin/sunreactorctl
# Render the unit for this distinct source-build path
mkdir -p ~/.config/systemd/user
sed "s|@BINDIR@|$HOME/.cargo/bin|g" contrib/systemd/sunreactord.service > ~/.config/systemd/user/sunreactord.service
systemd-analyze --user verify ~/.config/systemd/user/sunreactord.service
systemctl --user daemon-reload
systemctl --user enable --now sunreactord.serviceThis removes SunReactor completely: binaries, user unit, configuration, saved state, and cache.
curl -sL https://raw.githubusercontent.com/arcanorca/SunReactor/main/install.sh | bash -s -- --uninstallThe installer automatically adds every viable monitor with a safe, idempotent discovery step. To scan again later after connecting another display, run:
sunreactorctl discover --applyIt validates the updated configuration, avoids duplicate monitor entries, reloads the daemon, and rolls back if verification fails. Running it again is a no-op for monitors that are already configured.
Open the interactive terminal interface:
sunreactorctlThis starts the TUI. sunreactorctl tui is an equivalent explicit command.
Use Tab or the arrow keys to move between pages, Enter to edit or toggle a
setting, and q to save and quit. Go to Location, search for your city, and
select it; changes are saved and reloaded automatically. The Monitors and
Limits pages let you tune each display, while Weather and Settings
contain optional features.
Brightness changes are instant by default, which is safest for external DDC/CI monitors. If your display handles gradual fades reliably, enable them later in Settings → Fade brightness changes.
If the TUI reports a hardware or daemon problem, run:
sunreactorctl doctorThe remaining CLI commands are optional and useful for scripting or quick overrides:
sunreactorctl status # View current solar state and monitor levels
sunreactorctl suspend --minutes 60 # Temporarily pause automation
sunreactorctl set desk 50 # Manually override a specific monitor
sunreactorctl clear-override # Resume automatic solar policyThe TUI writes your settings to a standard TOML file at ~/.config/sunreactor/config.toml.
Newly discovered monitors start with a conservative 15% to 60% range; adjust it in
the Limits page when needed. Here is an example:
[location]
city = "Istanbul"
timezone = "Europe/Istanbul"
[daemon]
# Safe default for DDC/CI monitors: one direct brightness command per change.
# Set true only if your display reliably handles rapid multi-step fades.
smooth_transition = false
[[monitors]]
logical_id = "desk"
backend = "ddc"
min_pct = 15
max_pct = 60
gain = 1.0
[[monitors]]
logical_id = "laptop"
backend = "backlight"
min_pct = 15
max_pct = 60
gain = 1.2
sysfs_path = "/sys/class/backlight/amdgpu_bl1"
[weather]
enabled = true
provider = "openweather"
api_key_env = "OPENWEATHER_API_KEY"- Developer: arcanorca
- License: GPL-3.0-or-later
- Stack: Rust | ratatui | systemd (user) | Unix IPC | ddcutil | brightnessctl




