Bar Daemon

A daemon which uses tokio::UnixStream sockets to monitor system resources. It creates notifications via dunstify when resources change, as well as sending updates to all the UnixListener processes, so they are up to date without needing to wait for polling. Default polling rate is 2.0s, when each resource is updated or polled, the entire JSON for all resources is sent to all listeners.

The CLI for this application is written using Clap (Command Line Argument Parser), so each command and subcommand can be followed by help to learn more about it. Aliases are provided for all commands and subcommands, meaning they can be shortened.
bar_daemon g v p ≡ bar_daemon get volume percent


Monitored System Resources

Each monitored resource is programmed using traits so they all implement Monitored, any polled resources implement Polled, and there's also a Notify trait which is implemented by all types, but without a definition of notify() no notification is sent. The design for acquiring data is modular, such that, multiple sources can be separately implemented, e.g: instead of using wpctl for getting the volume, pactl could be implemented instead. All the resources' code is split into value.rs and source.rs, so that the acquisition of data and the manipulating of data is done seperately (This means that nothing in value.rs will change when different sources are implemented.)

Resource Command Name Description Notifies Polled
Volume wpctl Used to get and set the volume and mute state, and get the current icon. Performs a conversion from the internal linear volume to a displayed perceptual (logarithmic) volume. Yes No
Brightness brightnessctl Used to get and set the brightness of both the monitor and the keyboard, and get the current icon. Device IDs are hardcoded within the source code. Yes No
Battery acpi Used to get the current battery percentage, charging state, time remaining, and icon. Yes, at 5%, 15%, 20%, and 30% Yes
Bluetooth bluetooth
(bluetoothctl)
Used to get and set the bluetooth state, and the current icon. Yes No
Fan Speed asusctl Used to get and set the current Asus fan profile, and get the fan icon. Can be set as particular profile, or cycled using next or prev. Yes No
Memory free Used to get the currently used bytes, total bytes, used percentage of ram, and the icon. No Yes

Usage

Command Description
bar_daemon daemon Runs the daemon which will respond to get, set, and listen commands. Outputs errors and logs
bar_daemon listen Listens for changes in resources, and polled resources: receives JSON output of all resources on change.
bar_daemon get [RESOURCE] [VALUE_TYPE]
bar_daemon get volume percent
bar_daemon get ram icon
bar_daemon get brightness
Gets the value of the resource's value_type, or all values for that resource if no value_type is supplied. If no resource is provided, gets all values for all resources.
bar_daemon set <RESOURCE> <VALUE_TYPE> <VALUE>
bar_daemon set volume percent -20
bar_daemon set fan profile next
bar_daemon set brightness monitor 50
Sets the value of the requested resource. For brightness and volume delta values can be provided.

Log to Linear

The volume is modified so that each percentage step feels like the same increase in volume, while keeping the range as [0-100]. This fixes the issue where pipewire has imperceptible volume at low percentages, but unbearably high volume at high percentages. After trying various exponential values for the conversion between the perceptual volume and linear volume, I found that the best was actually 12.

#[must_use]
pub fn linear_to_logarithmic(linear_percent: f64) -> f64 {
    if linear_percent <= 0.0 {
        return 0.0;
    }

    if linear_percent >= 100.0 {
        return 100.0;
    }

    let normalized = linear_percent / 100.0;
    100.0 * (normalized.sqrt())
}

#[must_use]
pub fn logarithmic_to_linear(log_percent: f64) -> f64 {
    if log_percent <= 0.0 {
        return 0.0;
    }

    if log_percent >= 100.0 {
        return 100.0;
    }

    let normalized = log_percent / 100.0;
    100.0 * normalized.powi(2)
}

Phone

I am not comfortable putting my personal phone number on this public site, please use my email, or contact via LinkedIn.

Address

Newcastle Upon Tyne, NE5
United Kingdom