dendritic: rewrote entire config

This commit is contained in:
2026-05-23 20:18:11 +02:00
parent a93284ff80
commit c8ee6d85fe
190 changed files with 6764 additions and 8101 deletions
+450
View File
@@ -0,0 +1,450 @@
{ ... }: {
flake.nixosModules.battery-laptop = {
lib,
config,
...
}:
# https://discourse.nixos.org/t/what-is-the-best-option-for-power-management/63406/2
# we just activate tlp unconditonally
#let
# cfg = config.custom;
#hasBattery =
# lib.any (x: lib.strings.hasPrefix "BAT" x)
# (builtins.attrNames (builtins.readDir "/sys/class/power_supply"));
#in
{
# options.custom = {
# battery.enable = lib.mkOption {
# default = hasBattery;
# description = "Enable better battery support";
# type = lib.types.bool;
# };
# };
# config = lib.mkIf cfg.battery.enable {
powerManagement.powertop.enable = true; # enable powertop auto tuning on startup.
# Acording to https://community.frame.work/t/solved-keys-stick-and-repeat-after-being-released/51153/12
# Some powertop bug is responsable for the problem of the random keypress being stuck
# fix: from https://git.gabbie.blue/blue/nixconf/src/commit/2d1bc6dad4684c019b6b3e894408e76e2734806c/hosts/gabbielaptop/configuration.nix#L68
powerManagement.powertop.postStart = ''
${lib.getExe' config.systemd.package "udevadm"} trigger -c bind -s usb -a idVendor=32ac -a idProduct=0018
# Retrigger macropad udev rules
${lib.getExe' config.systemd.package "udevadm"} trigger -c bind -s usb -a idVendor=32ac -a idProduct=0013
'';
services.system76-scheduler.settings.cfsProfiles.enable = true; # Better scheduling for CPU cycles - thanks System76!!!
services.thermald.enable = true; # Enable thermald, the temperature management daemon. (only necessary if on Intel CPUs)
services.power-profiles-daemon.enable = false; # Disable GNOMEs power management
services.tlp = {
enable = true; # Enable TLP (better than gnomes internal power manager)
settings = {
CPU_BOOST_ON_AC = 1;
CPU_BOOST_ON_BAT = 1;
CPU_HWP_DYN_BOOST_ON_AC = 1;
CPU_HWP_DYN_BOOST_ON_BAT = 1;
CPU_SCALING_GOVERNOR_ON_AC = "performance";
CPU_SCALING_GOVERNOR_ON_BAT = "powersave";
CPU_ENERGY_PERF_POLICY_ON_AC = "performance";
CPU_ENERGY_PERF_POLICY_ON_BAT = "balance_power";
PLATFORM_PROFILE_ON_AC = "performance";
PLATFORM_PROFILE_ON_BAT = "balanced";
START_CHARGE_THRESH_BAT1 = 75;
STOP_CHARGE_THRESH_BAT1 = 85;
};
};
# };
};
flake.packages.batteryNotify = { pkgs, ... }: let
NotifySound = ../../assets/battery_notify.mp3;
in
pkgs.writeShellApplication {
# taken and adapted https://github.com/miniMinn24/Battery_Notify with MIT License
name = "custom-batterynotify";
runtimeInputs = with pkgs; [
mplayer
brightnessctl
];
text = ''
# Delay for startup
sleep 5
# Change your sound path here
playsound() {
mplayer ${NotifySound}
}
adjustBrightness() {
local adjustment="$1"
brightnessctl set "$adjustment"
}
sendNotification() {
local title="$1"
local message="$2"
notify-send -h string:x-canonical-private-synchronous:sys-notify -e -u low "$title" "$message"
}
# Runs full time in background
x=0
while true; do
Battery_Status="$(\cat /sys/class/power_supply/BAT*/status)"
Battery_Capacity=$(\cat /sys/class/power_supply/BAT*/capacity)
case "$Battery_Status" in
"Discharging")
if [ $x -eq 1 ]; then
sendNotification "Discharging" "Remains: <b>''${Battery_Capacity}%</b>"
adjustBrightness "15%-"
playsound
x=0
fi
;;
"Charging")
if [ $x -eq 0 ]; then
sendNotification "Charging" "Current: <b>''${Battery_Capacity}%</b>"
adjustBrightness "15%+"
playsound
x=1
fi
;;
"Full")
if [ $x -eq 0 ]; then
sendNotification "Fully Charged" "Noice: <b>''${Battery_Capacity}%</b>"
playsound
x=1
fi
;;
esac
sleep 1
done
'';
};
flake.packages.batteryWarning = { pkgs, ...}: let
NotifySound = ../../assets/battery_notify.mp3;
in
pkgs.writeShellApplication {
# taken and adapted https://github.com/miniMinn24/Battery_Notify with MIT License
name = "custom-batterywarning";
runtimeInputs = with pkgs; [
mplayer
brightnessctl
];
text = ''
# Delay for startup
sleep 5
playsound() {
mplayer ${NotifySound}
}
while true; do
Battery_Status="$(cat /sys/class/power_supply/BAT*/status)"
Battery_Capacity="$(cat /sys/class/power_supply/BAT*/capacity)"
if [ "$Battery_Status" == "Discharging" ]; then
if [ "$Battery_Capacity" -le 20 ] && [ "$Battery_Capacity" -ge 10 ]; then
notify-send -e -u critical "Battery Low!" "Power running out: <b>''${Battery_Capacity}%</b>"
playsound
sleep 180
elif [ "$Battery_Capacity" -lt 10 ]; then
notify-send -e -u critical "Battery Low!" "<b>Save your works</b> before immediate shutdown."
playsound
sleep 180
fi
else
sleep 120
fi
done
'';
};
flake.packages.qtbatticon = { pkgs, ... }:
# because cbatticon, batticonplus and other things didn't work.
# chatGpt did this.
# https://chatgpt.com/c/69da11b3-ba24-8331-b7b0-a58a72e69d42
# at your risk and perils
# click on the icon to get a notification with state, percentage and wattage
pkgs.stdenv.mkDerivation {
pname = "qtbatticon";
version = "1.0";
src = pkgs.writeTextFile {
name = "qtbatticon.cpp";
text = ''
#include <QApplication>
#include <QSystemTrayIcon>
#include <QTimer>
#include <QFile>
#include <QTextStream>
#include <QIcon>
#include <QString>
#include <QDebug>
#include <cstdlib>
QString readFile(const QString &path) {
QFile f(path);
if (!f.open(QIODevice::ReadOnly)) return "";
QTextStream in(&f);
return in.readAll().trimmed();
}
int readInt(const QString &path) {
return readFile(path).toInt();
}
double readDouble(const QString &path) {
QFile f(path);
if (!f.open(QIODevice::ReadOnly)) return 0;
QTextStream in(&f);
return in.readAll().trimmed().toDouble();
}
int toStep(int capacity) {
return (capacity / 10) * 10;
}
QString pad3(int n) {
return QString("%1").arg(n, 3, 10, QChar('0'));
}
double getPowerW(const QString &batPath) {
double current_uA = readDouble(batPath + "/current_now");
double voltage_uV = readDouble(batPath + "/voltage_now");
if (current_uA > 0 && voltage_uV > 0) {
return (current_uA * voltage_uV) / 1e12;
}
return -1;
}
QIcon batteryIcon(int capacity, bool charging) {
int step = toStep(capacity);
QString num = pad3(step);
QString base = "/run/current-system/sw/share/icons/Papirus/24x24/panel/";
QString file;
if (charging) {
file = base + "battery-" + num + "-charging.svg";
} else {
file = base + "battery-" + num + ".svg";
}
QIcon icon(file);
if (icon.isNull()) {
qDebug() << "FAILED icon:" << file;
icon = QIcon(base + "battery-100.svg");
}
return icon;
}
void sendNotification(const QString &title, const QString &body) {
QString cmd = "notify-send \"" + title + "\" \"" + body + "\"";
system(cmd.toUtf8().constData());
}
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QString batPath = "/sys/class/power_supply/BAT1";
QSystemTrayIcon tray;
auto updateIcon = [&]() {
int capacity = readInt(batPath + "/capacity");
QString status = readFile(batPath + "/status");
bool charging = status.contains("Charging");
tray.setIcon(batteryIcon(capacity, charging));
};
auto notify = [&]() {
int capacity = readInt(batPath + "/capacity");
QString status = readFile(batPath + "/status");
bool charging = status.contains("Charging");
bool discharging = status.contains("Discharging");
double power = getPowerW(batPath);
QString state;
if (charging) state = "Charging";
else if (discharging) state = "Discharging";
else state = status;
QString powerStr = (power > 0.01)
? QString::number(power, 'f', 2) + " W"
: "N/A";
QString msg =
QString("%1\n%2%\n%3")
.arg(state)
.arg(capacity)
.arg(powerStr);
sendNotification("Battery status", msg);
};
QObject::connect(&tray, &QSystemTrayIcon::activated,
[&](QSystemTrayIcon::ActivationReason r) {
if (r == QSystemTrayIcon::Trigger) {
notify();
}
});
updateIcon();
tray.setVisible(true);
QTimer timer;
QObject::connect(&timer, &QTimer::timeout, updateIcon);
timer.start(5000);
return app.exec();
}
'';
};
nativeBuildInputs = with pkgs; [
pkg-config
qt6.wrapQtAppsHook
];
buildInputs = with pkgs; [
qt6.qtbase
qt6.qtsvg
papirus-icon-theme
];
dontUnpack = true;
buildPhase = ''
g++ $src -o qtbatticon \
$(pkg-config --cflags --libs Qt6Widgets)
'';
installPhase = ''
mkdir -p $out/bin
install -m755 qtbatticon $out/bin/
'';
};
# This was replaced by caelestia shell's Game Mode
flake.packages.custom-performance = { pkgs, ...}:
pkgs.writeShellApplication {
name = "custom-performance";
runtimeInputs = with pkgs; [
hyprland
gawk
libnotify
];
text = ''
HYPRGAMEMODE=$(hyprctl getoption animations:enabled | awk 'NR==1{print $2}')
if [ "$HYPRGAMEMODE" = 1 ] ; then
hyprctl --batch "\
keyword animations:enabled 0;\
keyword animation borderangle,0; \
keyword decoration:shadow:enabled 0;\
keyword decoration:blur:enabled 0;\
keyword decoration:fullscreen_opacity 1;\
keyword general:gaps_in 0;\
keyword general:gaps_out 0;\
keyword general:border_size 1;\
keyword decoration:rounding 0"
notify-send -u critical -t 5000 "Performance mode [ON]"
exit
else
notify-send -u critical -t 5000 "Performance mode [OFF]"
hyprctl reload
exit 0
fi
'';
};
# Old script that was used for the battery. Might not work.
flake.packages.custom-olddeprecatedbatterynotify = { pkgs, ... }:
pkgs.writeShellApplication {
name = "custom-olddeprecatedbatterynotify";
runtimeInputs = with pkgs; [
libnotify # provides notify-send
systemd # provides systemctl
];
text = ''
set -euo pipefail
LOW="''${BATTERY_LOW_THRESHOLD:-20}"
CRITICAL="''${BATTERY_CRITICAL_THRESHOLD:-5}"
FULL="''${BATTERY_FULL_THRESHOLD:-95}"
INTERVAL="''${BATTERY_INTERVAL:-30}"
ACTION="''${BATTERY_CRITICAL_ACTION:-systemctl suspend}"
notify() {
notify-send -a "Battery" -u "$1" "$2" "$3"
}
get_info() {
total=0
count=0
for bat in /sys/class/power_supply/BAT*; do
[ -f "$bat/capacity" ] || continue
capacity=$(<"$bat/capacity")
status=$(<"$bat/status")
total=$((total + capacity))
count=$((count + 1))
done
[ "$count" -gt 0 ] || exit 0
percentage=$((total / count))
}
last_state=""
while true; do
get_info
if [[ "$status" == "Discharging" && "$percentage" -le "$CRITICAL" ]]; then
notify critical "Battery Critically Low" "$percentage% suspending."
$ACTION
elif [[ "$status" == "Discharging" && "$percentage" -le "$LOW" ]]; then
if [[ "$last_state" != "low" ]]; then
notify normal "Battery Low" "$percentage% remaining."
last_state="low"
fi
elif [[ "$status" != "Discharging" && "$percentage" -ge "$FULL" ]]; then
if [[ "$last_state" != "full" ]]; then
notify normal "Battery Full" "$percentage% unplug charger."
last_state="full"
fi
else
last_state=""
fi
sleep "$INTERVAL"
done
'';
};
flake.homeModules.cbatticon = { ... }: {
# don't works. some GTK error. I let it here if someday, someone is interest in this shit.
# ChatGPT half baked a replacement that works on my system.
# see qtbatticon
services.cbatticon = {
enable = true;
lowLevelPercent = 20;
criticalLevelPercent = 5;
batteryId = "BAT1";
hideNotification = true; # we use another script for battery notifications
updateIntervalSeconds = 10;
};
};
}
+8
View File
@@ -0,0 +1,8 @@
{ inputs, ...}: {
flake.nixosModule.bluetooth = {pkgs, ...}: {
hardware.bluetooth.enable = true;
environment.systemPackages = with pkgs; [
blueman # GTK-based Bluetooth Manager
];
};
}
+16
View File
@@ -0,0 +1,16 @@
{ ... }: {
flake.nixosModules.bootloader-laptop = {
inputs,
pkgs,
...
}: {
# grub theme
boot.loader.grub = {
theme = inputs.nixos-grub-themes.packages.${pkgs.system}.nixos; # if you want to use nixos grub theme
};
# Bootloader.
boot.loader.systemd-boot.enable = true;
boot.loader.efi.canTouchEfiVariables = true;
};
}
+18
View File
@@ -0,0 +1,18 @@
{ ... }: {
flake.nixosModule.disk = { pkgs, ... }: {
environment.systemPackages = with pkgs; [
gnome-disk-utility
udiskie
];
};
flake.nixosModule.disk-laptop = { ... }: {
# i found swap necessary when running nixpkgs review
swapDevices = [
{
device = "/swapfile";
size = 16384; # 16 GB
}
];
boot.kernel.sysctl."vm.swappiness" = 10;
};
}
@@ -0,0 +1,36 @@
{ ... }: {
flake.nixosModules.hardware-configuration-laptop = {
config,
lib,
modulesPath,
...
}: {
# Do not modify this file! It was generated by nixos-generate-config
# and may be overwritten by future invocations. Please make changes
# to /etc/nixos/configuration.nix instead.
imports = [
(modulesPath + "/installer/scan/not-detected.nix")
];
boot.initrd.availableKernelModules = ["nvme" "xhci_pci" "thunderbolt" "usb_storage" "usbhid" "sd_mod"];
boot.initrd.kernelModules = [];
boot.kernelModules = ["kvm-amd"];
boot.extraModulePackages = [];
fileSystems."/" = {
device = "/dev/disk/by-uuid/6aa664c2-8b23-4e20-b6e9-1806bf0f8df2";
fsType = "ext4";
};
fileSystems."/boot" = {
device = "/dev/disk/by-uuid/A59A-7AFA";
fsType = "vfat";
options = ["fmask=0077" "dmask=0077"];
};
swapDevices = [];
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
};
}
+10
View File
@@ -0,0 +1,10 @@
{ ... }: {
flake.nixosModules.hardwareUtils-laptop = {pkgs, ...}: {
environment.systemPackages = with pkgs; [
# used for the framework 16 laptop
framework-tool
framework-tool-tui
vial # Open-source GUI and QMK fork for configuring your keyboard in real time
];
};
}
+22
View File
@@ -0,0 +1,22 @@
{ ... }: {
flake.nixosModules.udev = { ... }: {
# udev with only the necessary rules. See udev.nix to get all the rules
services.udev.extraRules = ''
# adapted from here https://wiki.nixos.org/wiki/Keychron_M6
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="32ac", MODE="0660", GROUP="users", TAG+="uaccess"
# taken from here
SUBSYSTEMS=="usb", ATTRS{idVendor}=="32ac", ATTRS{idProduct}=="0013", TAG+="uaccess"
SUBSYSTEMS=="usb", ATTRS{idVendor}=="32ac", ATTRS{idProduct}=="0018", TAG+="uaccess"
# acording to https://community.frame.work/t/solved-keys-stick-and-repeat-after-being-released/51153/12
# the random keypress stuck comes from conflict between powertop and udev
# fix from: https://git.gabbie.blue/blue/nixconf/src/commit/2d1bc6dad4684c019b6b3e894408e76e2734806c/hosts/gabbielaptop/configuration.nix#L68
# disable USB auto suspend for framework keyboard
ACTION=="bind", SUBSYSTEM=="usb", ATTR{idVendor}=="32ac", ATTR{idProduct}=="0018", TEST=="power/control", ATTR{power/control}="on"
# disable USB auto suspend for framework macropad
ACTION=="bind", SUBSYSTEM=="usb", ATTR{idVendor}=="32ac", ATTR{idProduct}=="0013", TEST=="power/control", ATTR{power/control}="on"
'';
};
}