aboutsummaryrefslogtreecommitdiffstats
path: root/roles
diff options
context:
space:
mode:
authorPetri Hienonen <petri.hienonen@gmail.com>2024-05-23 13:56:00 +0300
committerPetri Hienonen <petri.hienonen@gmail.com>2025-11-30 12:29:57 +0200
commit08297376a85a1719518507e54fca9de954d2376a (patch)
tree3b9c58304b40248533bbb2bb5b7bad2da9da1ff0 /roles
parent75c2af4aedd2ac5c2cfc74b346625fa4b265541d (diff)
downloadnixos-08297376a85a1719518507e54fca9de954d2376a.tar.zst
Agenix configuration
Diffstat (limited to 'roles')
-rw-r--r--roles/shared.nix818
-rw-r--r--roles/wallpaper.nix23
2 files changed, 841 insertions, 0 deletions
diff --git a/roles/shared.nix b/roles/shared.nix
new file mode 100644
index 0000000..47aaf6f
--- /dev/null
+++ b/roles/shared.nix
@@ -0,0 +1,818 @@
+{
+ pkgs,
+ vars,
+ lib,
+ inputs,
+ config,
+ agenix,
+ ...
+}:
+
+{
+ age = {
+ identityPaths = [ "/home/petri/.ssh/id_ed25519" ];
+ secrets = {
+ s3fs.file = ../secrets/s3fs.age;
+ duckdns.file = ../secrets/duckdns_login_token.age;
+ };
+ };
+
+ nixpkgs.config = {
+ allowUnfree = true;
+ qt.enable = true;
+ };
+ nix = {
+ optimise = {
+ automatic = true;
+ };
+ sshServe = {
+ trusted = true;
+ enable = true;
+ };
+ daemonCPUSchedPolicy = "idle";
+ daemonIOSchedClass = "idle";
+ gc = {
+ automatic = true;
+ };
+ settings = {
+ #substituters = [ "https://nix-community.cachix.org" ];
+ #trusted-public-keys = [ "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" ];
+ trusted-users = [ "${vars.user}" ];
+ auto-optimise-store = true;
+ nix-path = [ "nixpkgs=${pkgs.path}" ];
+ experimental-features = "nix-command flakes";
+ system-features = [
+ "benchmark"
+ "big-parallel"
+ "kvm"
+ "gccarch-x86-64-v3"
+ ];
+ };
+ registry = (lib.mapAttrs (_: flake: { inherit flake; })) (
+ (lib.filterAttrs (_: lib.isType "flake")) inputs
+ );
+ extraOptions = ''
+ http2 = true
+ keep-outputs = true
+ keep-derivations = true
+ '';
+ };
+ system.switch = {
+ enable = false;
+ enableNg = true;
+ };
+
+ system.activationScripts.diff = {
+ supportsDryActivation = true;
+ text = ''
+ ${pkgs.nvd}/bin/nvd --nix-bin-dir=${pkgs.nix}/bin diff \
+ /run/current-system "$systemConfig"
+ '';
+ };
+
+ zramSwap = {
+ enable = true;
+ algorithm = "zstd";
+ };
+
+ boot = {
+ tmp = {
+ tmpfsHugeMemoryPages = "within_size";
+ useTmpfs = true;
+ };
+ binfmt.emulatedSystems = [
+ "aarch64-linux"
+ "riscv64-linux"
+ ];
+ kernel.sysctl = {
+ "kernel.sysrq" = 1;
+ "net.core.netdev_max_backlog" = 25000;
+ "net.core.rmem_default" = 67108864; # allow network stack 64MB
+ "net.core.rmem_max" = 67108864; # allow network stack 64MB
+ "net.core.wmem_default" = 67108864;
+ "net.core.wmem_max" = 67108864;
+ "net.core.default_qdisc" = "fq";
+
+ "net.ipv4.tcp_congestion_control" = "bbr";
+ "net.ipv4.tcp_ecn" = 1;
+ "net.ipv4.tcp_fastopen" = 3;
+ "net.ipv4.tcp_fin_timeout" = 10;
+ "net.ipv4.tcp_low_latency" = 1;
+ "net.ipv4.tcp_mtu_probing" = 2; # recommended for hosts with jumbo frames enabled
+ "net.ipv4.tcp_no_metrics_save" = 1;
+ "net.ipv4.tcp_rmem" = "4096 87380 33554432"; # increase Linux autotuning TCP buffer limit to 32MB
+ "net.ipv4.tcp_slow_start_after_idle" = 0;
+ "net.ipv4.tcp_syncookies" = 1;
+ "net.ipv4.tcp_timestamps" = 1;
+ "net.ipv4.tcp_wmem" = "4096 65536 33554432";
+ "net.ipv6.conf.default.accept_ra" = 2;
+ "net.ipv6.conf.default.router_solicitations" = 3;
+ "net.ipv6.conf.default.router_solicitation_interval" = 1;
+ "net.ipv6.conf.default.router_solicitation_delay" = 0;
+ "net.ipv6.conf.default.dad_transmits" = 1;
+ "net.ipv6.conf.default.accept_dad" = 1;
+ "net.ipv6.conf.default.optimistic_dad" = 1;
+ "net.mptcp.enabled" = 1;
+
+ "vm.nr_hugepages" = 512;
+ "vm.dirty_background_ratio" = 5;
+ "vm.swappiness" = 10;
+ "kernel.sched_wakeup_granularity_ns" = 500000;
+ };
+ loader = {
+ systemd-boot = {
+ memtest86.enable = true;
+ configurationLimit = lib.mkDefault 8;
+ consoleMode = lib.mkDefault "max";
+ enable = true;
+ };
+ efi.canTouchEfiVariables = true;
+ };
+ initrd = {
+ systemd = {
+ enable = true;
+ dbus.enable = true;
+ network = {
+ enable = true;
+ networks."99-dhcp" = {
+ matchConfig.Name = "*";
+ networkConfig.DHCP = "yes";
+ };
+ };
+ };
+ };
+ };
+
+ networking = {
+ nftables.enable = true;
+ useDHCP = false;
+ firewall = {
+ enable = true;
+ allowPing = true;
+ allowedTCPPorts = [
+ 22
+ 443
+ 5353
+ ];
+ };
+ wireless.iwd = {
+ enable = true;
+ settings = {
+ Network = {
+ EnableIPv6 = true;
+ };
+ };
+ };
+ useNetworkd = true;
+ nameservers = [
+ "2001:14ba:a300:e5ba::1#adguard.tammi.cc"
+ "87.92.90.90#adguard.tammi.cc"
+ ];
+ };
+
+ systemd = {
+ user.tmpfiles.users = {
+ ${vars.user}.rules = [ "D %C - - - 7d" ];
+ };
+ tmpfiles.rules = [
+ "d /tmp 1777 root root 10d"
+ "d /run/pam_timestamp 0700 root root -"
+ ];
+ services = {
+ "systemd-networkd".environment.SYSTEMD_LOG_LEVEL = "debug";
+ };
+ extraConfig = ''
+ DefaultTimeoutStopSec=10
+ DefaultLimitNOFILE=2048
+ '';
+ # watchdog = {
+ # device = "/dev/watchdog";
+ # runtimeTime = "30s";
+ #};
+ sleep.extraConfig = ''
+ AllowSuspend=yes
+ AllowHibernation=yes
+ AllowHybridSleep=yes
+ AllowSuspendThenHibernate=yes
+ HibernateDelaySec=3600
+ '';
+
+ services.nix-daemon = {
+ environment.TMPDIR = "/var/tmp";
+ };
+ };
+
+ powerManagement = {
+ enable = true;
+ };
+
+ console = {
+ font = "${pkgs.tamzen}/share/consolefonts/Tamzen8x16.psf";
+ packages = with pkgs; [ tamzen ];
+ earlySetup = true;
+ colors = [
+ "3b4252"
+ "bf616a"
+ "a3be8c"
+ "ebcb8b"
+ "81a1c1"
+ "b48ead"
+ "88c0d0"
+ "e5e9f0"
+ "4c566a"
+ "bf616a"
+ "a3be8c"
+ "ebcb8b"
+ "81a1c1"
+ "b48ead"
+ "8fbcbb"
+ "eceff4"
+ ];
+ keyMap = "us";
+ };
+
+ security = {
+ pam.services = {
+ hyprlock = { };
+ greetd = {
+ enableGnomeKeyring = true;
+ };
+ };
+ polkit = {
+ enable = true;
+ extraConfig = ''
+ polkit.addRule(function(action, subject) {
+ if (subject.isInGroup("wheel") && subject.local) {
+ // Always allow local wheel users without password
+ return polkit.Result.YES;
+ }
+ });
+ '';
+ };
+ rtkit.enable = true;
+ sudo.extraConfig = ''
+ Defaults timestamp_timeout=60
+ '';
+ };
+
+ time.timeZone = "Europe/Helsinki";
+
+ i18n = {
+ defaultLocale = "en_US.UTF-8";
+ extraLocaleSettings = {
+ LC_ADDRESS = "fi_FI.UTF-8";
+ LC_IDENTIFICATION = "fi_FI.UTF-8";
+ LC_MEASUREMENT = "fi_FI.UTF-8";
+ LC_MONETARY = "fi_FI.UTF-8";
+ LC_NAME = "fi_FI.UTF-8";
+ LC_NUMERIC = "fi_FI.UTF-8";
+ LC_PAPER = "fi_FI.UTF-8";
+ LC_TELEPHONE = "fi_FI.UTF-8";
+ LC_TIME = "fi_FI.UTF-8";
+ };
+ extraLocales = [ "fi_FI.UTF-8/UTF-8" ];
+ };
+
+ users.users.${vars.user} = {
+ isNormalUser = true;
+ description = "${vars.name}";
+ extraGroups = [
+ "adm"
+ "audio"
+ "bluetooth"
+ "input"
+ "lp"
+ "network"
+ "plugdev"
+ "render"
+ "systemd-journal"
+ "video"
+ "wheel"
+ "wireshark"
+ "render"
+ ];
+ ignoreShellProgramCheck = true;
+ packages = with pkgs; [
+ alsa-utils
+ blis
+ bluez
+ bluez-tools
+ bluez-alsa
+ glfw
+ glm
+ glxinfo
+ gotop
+ libva
+ libva-utils
+ nixfmt-rfc-style
+ shaderc.static
+ shaderc.dev
+ vulkan-headers
+ vulkan-loader
+ vulkan-tools
+ vulkan-validation-layers
+ ];
+ shell = pkgs.${vars.shell};
+ openssh.authorizedKeys.keys = [
+ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHIXKjutIlv3CS9dmo9bDUUt3UR9O9xUKFXzci3LvNTQ petri.hienonen@gmail.com"
+ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJzUFgqZF3U6RfbvQLKBdzNgWHGp3z+9FGvqjgTY8N6K petri@saarni"
+ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIimbOBDKbTNi8b+P0wWaZRszRV59lnokqrGQRIdgqOj petri@kataja"
+ ];
+ };
+
+ environment = {
+ systemPackages = with pkgs; [
+ agenix.packages.${system}.default
+ clinfo
+ coreutils
+ curl
+ git
+ gnumake
+ gnupg
+ greetd.tuigreet
+ linux-firmware
+ lm_sensors
+ mimalloc
+ minio-client
+ neovim
+ nvd
+ procps
+ s3fs
+ sysfsutils
+ unrar
+ unzip
+ usbutils
+ zstd
+ ];
+ variables = {
+ EDITOR = "${pkgs.neovim}/bin/nvim";
+ LD_LIBRARY_PATH = "${pkgs.vulkan-loader}/lib:$LD_LIBRARY_PATH";
+ NIXPKGS_ALLOW_UNFREE = 1;
+ QT_QPA_PLATFORM = "xcb";
+ SYSTEMD_COLORS = 256;
+ SYSTEMD_LOG_COLOR = 1;
+ SYSTEMD_URLIFY = 1;
+ VULKAN_SDK = "${pkgs.vulkan-headers}";
+ };
+ };
+
+ fileSystems."/media/llm" = {
+ device = "llm";
+ fsType = "fuse./run/current-system/sw/bin/s3fs";
+ noCheck = true;
+ options = [
+ "_netdev"
+ "allow_other"
+ "umask=0007"
+ "uid=1000"
+ "use_path_request_style"
+ "url=https://s3.tammi.cc"
+ "passwd_file=${config.age.secrets.s3fs.path}"
+ ];
+ };
+
+ fileSystems."/media/skydrive" = {
+ device = "skydrive";
+ fsType = "fuse./run/current-system/sw/bin/s3fs";
+ noCheck = true;
+ options = [
+ "_netdev"
+ "allow_other"
+ "umask=0007"
+ "uid=1000"
+ "use_path_request_style"
+ "url=https://s3.tammi.cc"
+ "passwd_file=${config.age.secrets.s3fs.path}"
+ ];
+ };
+
+ fonts = {
+ enableDefaultPackages = true;
+ packages = with pkgs; [
+ nerd-fonts.iosevka
+ nerd-fonts.iosevka-term
+ nerd-fonts.zed-mono
+ nixos-icons
+ roboto-serif
+ roboto-mono
+ roboto-flex
+ twitter-color-emoji
+ ];
+ fontDir.enable = true;
+ fontconfig = {
+ enable = true;
+ hinting = {
+ enable = true;
+ autohint = true;
+ style = "medium";
+ };
+ useEmbeddedBitmaps = true;
+ cache32Bit = true;
+ antialias = true;
+ subpixel = {
+ rgba = lib.mkDefault "rgb";
+ lcdfilter = "default";
+ };
+ defaultFonts = {
+ serif = [ "Roboto Serif" ];
+ sansSerif = [ "Roboto Flex" ];
+ monospace = [ "Iosevka Nerd Font" ];
+ emoji = [ "Twitter Color Emoji" ];
+ };
+ };
+ };
+
+ programs = {
+ ssh = {
+ extraConfig = ''
+ Compression = yes
+ ControlMaster = yes
+ Protocol = 2
+ ServerAliveInterval = 1
+ ServerAliveCountMax = 3
+ TCPKeepAlive = yes
+ '';
+ hostKeyAlgorithms = [
+ "ssh-ed25519-cert-v01@openssh.com"
+ "ssh-rsa-cert-v01@openssh.com"
+ "ssh-ed25519"
+ "ssh-rsa"
+ "ecdsa-sha2-nistp521-cert-v01@openssh.com"
+ "ecdsa-sha2-nistp384-cert-v01@openssh.com"
+ "ecdsa-sha2-nistp256-cert-v01@openssh.com"
+ "ecdsa-sha2-nistp521"
+ "ecdsa-sha2-nistp384"
+ "ecdsa-sha2-nistp256"
+ ];
+ kexAlgorithms = [
+ "curve25519-sha256@libssh.org"
+ "ecdh-sha2-nistp521"
+ "ecdh-sha2-nistp384"
+ "ecdh-sha2-nistp256"
+ "diffie-hellman-group-exchange-sha256"
+ ];
+ macs = [
+ "hmac-sha2-512-etm@openssh.com"
+ "hmac-sha2-256-etm@openssh.com"
+ "umac-128-etm@openssh.com"
+ "hmac-sha2-512"
+ "hmac-sha2-256"
+ "umac-128@openssh.com"
+ ];
+ ciphers = [
+ "chacha20-poly1305@openssh.com"
+ "aes256-gcm@openssh.com"
+ "aes128-gcm@openssh.com"
+ "aes256-ctr"
+ "aes192-ctr"
+ "aes128-ctr"
+ ];
+
+ };
+ arp-scan.enable = true;
+ appimage = {
+ enable = true;
+ binfmt = true;
+ };
+ ccache.enable = true;
+ wireshark.enable = true;
+ command-not-found.enable = false; # enabled by default, does not work with flakes
+ dconf.enable = true; # needed by gnome application, such as firefox
+ mosh = {
+ enable = true;
+ withUtempter = true;
+ openFirewall = true;
+ };
+ xwayland.enable = true;
+ gnupg.agent = {
+ enable = true;
+ enableSSHSupport = true;
+ };
+ alvr = {
+ enable = true;
+ openFirewall = true;
+ };
+ gamescope = {
+ enable = true;
+ };
+ steam = {
+ enable = true;
+ gamescopeSession.enable = true;
+ remotePlay.openFirewall = true; # Open ports in the firewall for Steam Remote Play
+ dedicatedServer.openFirewall = true; # Open ports in the firewall for Source Dedicated Server
+ localNetworkGameTransfers.openFirewall = true; # Open ports in the firewall for Steam Local Network Ga
+ extraCompatPackages = [ pkgs.proton-ge-bin ];
+ };
+ };
+
+ systemd.network.networks."50-bluetooth-pan" = {
+ matchConfig.Name = "bnep*";
+ networkConfig = {
+ DHCP = true;
+ IPv6AcceptRA = true;
+ };
+ };
+
+ hardware = {
+ enableAllFirmware = true;
+ enableRedistributableFirmware = true;
+ graphics = {
+ enable = true;
+ };
+ bluetooth = {
+ enable = true;
+ powerOnBoot = true;
+ settings = {
+ General = {
+ ControllerMode = "bredr";
+ DiscoverableTimeout = 0;
+ Experimental = true;
+ FastConnectable = true;
+ JustWorksRepairing = "always";
+ KernelExperimental = true;
+ MultiProfile = "multiple";
+ Privacy = "off";
+ Testing = true;
+ };
+ Policy = {
+ AutoEnable = true;
+ };
+ LE = {
+ ConnectionLatency = 0;
+ ConnectionSupervisionTimeout = 2000;
+ EnableAdvMonInterleaveScan = 1;
+ MaxConnectionInterval = 16;
+ MinConnectionInterval = 16;
+ ScanIntervalAutoConnect = 300;
+ };
+ GATT = {
+ Channels = 6;
+ };
+ };
+ };
+ };
+
+ services = {
+ pipewire = {
+ enable = true;
+ alsa.enable = true;
+ pulse = {
+ enable = true;
+
+ };
+ audio.enable = true;
+ wireplumber = {
+ enable = true;
+ extraConfig = {
+ "10-bluez" = {
+ "monitor.bluez.properties" = {
+ "bluez5.enable-sbc-xq" = true;
+ "bluez5.enable-msbc" = true;
+ "bluez5.enable-hw-volume" = true;
+ "bluez5.roles" = [
+ "hsp_hs"
+ "hsp_ag"
+ "hfp_hf"
+ "hfp_ag"
+ ];
+ };
+ };
+ };
+ };
+ extraConfig.pipewire-pulse = {
+ "switch-on-connect.conf" = {
+ "pulse.cmd" = [
+ {
+ cmd = "load-module";
+ args = "module-switch-on-connect";
+ }
+ ];
+ };
+ };
+ };
+ libinput = {
+ enable = true;
+ };
+ geoclue2 = {
+ package = pkgs.geoclue2-with-demo-agent;
+ enableDemoAgent = true;
+ enable = true;
+ };
+ systembus-notify.enable = true;
+ dbus = {
+ implementation = "broker";
+ packages = [ pkgs.bluez ];
+ };
+ timesyncd = {
+ enable = true;
+ servers = [
+ "time1.mikes.fi"
+ "time2.mikes.fi"
+ ];
+ };
+ printing.enable = true;
+ upower = {
+ enable = true;
+ };
+ devmon.enable = true; # automatic device mounting daemon
+ journald = {
+ audit = true;
+ extraConfig = ''
+ ReadKMsg=1
+ SystemMaxUse=200M
+ '';
+ };
+ xserver = {
+ enable = true; # Required by steam
+ xkb = {
+ layout = "us";
+ variant = "";
+ };
+ updateDbusEnvironment = true;
+ };
+ udev.extraRules = ''
+ # Blinkstick nano
+ SUBSYSTEM=="usb", ATTR{idVendor}=="20a0", ATTR{idProduct}=="41e5", MODE:="0666"
+ # ESP32 waveshare
+ SUBSYSTEM=="usb", ATTR{idVendor}=="1a86", ATTR{idProduct}=="55d3", MODE:="0666"
+ '';
+ getty.autologinUser = "${vars.user}";
+ kmscon = {
+ enable = true;
+ hwRender = true;
+ extraOptions = "--xkb-layout=fi";
+ fonts = [
+ {
+ name = "Iosevka Nerd Font";
+ package = pkgs.nerd-fonts.iosevka;
+ }
+ ];
+ };
+ openssh = {
+ enable = true;
+ openFirewall = true;
+ settings = {
+ UseDns = true;
+ AllowUsers = [ "petri" ];
+ KexAlgorithms = [
+ "curve25519-sha256@libssh.org"
+ "ecdh-sha2-nistp521"
+ "ecdh-sha2-nistp384"
+ "ecdh-sha2-nistp256"
+ "diffie-hellman-group-exchange-sha256"
+ ];
+ Ciphers = [
+ "chacha20-poly1305@openssh.com"
+ "aes256-gcm@openssh.com"
+ "aes128-gcm@openssh.com"
+ "aes256-ctr"
+ "aes192-ctr"
+ "aes128-ctr"
+ ];
+ Macs = [
+ "hmac-sha2-512-etm@openssh.com"
+ "hmac-sha2-256-etm@openssh.com"
+ "umac-128-etm@openssh.com"
+ "hmac-sha2-512"
+ "hmac-sha2-256"
+ "umac-128@openssh.com"
+ ];
+ PermitRootLogin = "no";
+ PasswordAuthentication = false;
+ };
+ extraConfig = ''
+ ClientAliveCountMax 0
+ ClientAliveInterval 300
+
+ LoginGraceTime 60
+ AllowTcpForwarding no
+ AllowAgentForwarding no
+ MaxAuthTries 3
+ MaxSessions 2
+ TCPKeepAlive no
+ '';
+ };
+ earlyoom = {
+ enableNotifications = true;
+ enable = true;
+ };
+ ananicy = {
+ enable = true;
+ package = pkgs.ananicy-cpp;
+ rulesProvider = pkgs.ananicy-rules-cachyos;
+ };
+ fwupd = {
+ enable = true;
+ extraRemotes = [ "lvfs-testing" ];
+ };
+ resolved = {
+ enable = true;
+ dnssec = "true";
+ llmnr = "true";
+ dnsovertls = "true";
+ domains = [ "~." ];
+ extraConfig = ''
+ MulticastDNS=true
+ Cache=no-negative
+ '';
+ fallbackDns = [
+ "2606:4700:4700::1111#cloudflare-dns.com"
+ "2606:4700:4700::1001#cloudflare-dns.com"
+ "1.1.1.1#cloudflare-dns.com"
+ "1.0.0.1#cloudflare-dns.com"
+ "9.9.9.9#dns.quad9.net"
+ "149.112.112.112#dns.quad9.net"
+ ];
+ };
+ fstrim.enable = true;
+ smartd = {
+ notifications = {
+ test = true;
+ systembus-notify.enable = true;
+ };
+ enable = true;
+ };
+ greetd = {
+ enable = true;
+ vt = 1;
+ restart = true;
+ settings = {
+ initial_session = {
+ command = "/etc/greetd/hyprland-wrapper.sh";
+ user = "${vars.user}";
+ };
+ default_session = {
+ command = "${pkgs.greetd.tuigreet}/bin/tuigreet --cmd /etc/greetd/hyprland-wrapper.sh";
+ };
+ };
+ };
+ };
+
+ environment.etc = {
+ "greetd/hyprland-wrapper.sh" = {
+ text = ''
+ #!/bin/sh
+ # Session
+ export XDG_SESSION_TYPE=wayland
+ export XDG_SESSION_DESKTOP=Hyprland
+ export XDG_CURRENT_DESKTOP=Hyprland
+
+ # Wayland stuff
+ export MOZ_ENABLE_WAYLAND=1
+ export QT_QPA_PLATFORM=wayland
+ export SDL_VIDEODRIVER=wayland
+
+ dbus-run-session ${pkgs.hyprland}/bin/Hyprland
+ '';
+ mode = "0755";
+ };
+ "bluetooth-tether.sh" = {
+ mode = "0755";
+ text = ''
+ #!/bin/sh
+ DEVICE_MAC="3C:01:EF:D9:0D:96" # Phone shares the internet
+ ADAPTER="hci0" # Replace if your adapter is different (check with `bluetoothctl list`)
+
+ # Ensure Bluetooth is powered on
+ ${pkgs.bluez}/bin/bluetoothctl power on
+
+ # Scan for the device briefly (5 seconds)
+ ${pkgs.bluez}/bin/bluetoothctl scan on &
+ sleep 5
+ ${pkgs.bluez}/bin/bluetoothctl scan off
+
+ # Check if the device is present
+ if ${pkgs.bluez}/bin/bluetoothctl devices | grep -q "$DEVICE_MAC"; then
+ echo "Device $DEVICE_MAC found, attempting to connect to NAP..."
+ # Ensure device is trusted (optional, for reliability)
+ ${pkgs.bluez}/bin/bluetoothctl trust "$DEVICE_MAC"
+ # Connect to NAP profile
+ ${pkgs.dbus}/bin/dbus-send --system --type=method_call --dest=org.bluez \
+ /org/bluez/$ADAPTER/dev_$(echo $DEVICE_MAC | tr ':' '_') \
+ org.bluez.Network1.Connect string:'nap' || {
+ echo "Failed to connect to NAP for $DEVICE_MAC"
+ exit 1
+ }
+ echo "Connected to NAP for $DEVICE_MAC"
+ else
+ echo "Device $DEVICE_MAC not found, skipping connection"
+ exit 0
+ fi
+ '';
+ };
+ };
+
+ systemd.services.bluetooth-tether = {
+ description = "Auto-connect to Bluetooth tethering PAN if device is detected";
+ after = [ "bluetooth.service" ];
+ partOf = [ "bluetooth.service" ];
+ wantedBy = [ "multi-user.target" ];
+ serviceConfig = {
+ Type = "oneshot";
+ ExecStart = "/etc/bluetooth-tether.sh";
+ RemainAfterExit = true;
+ Restart = "on-failure";
+ RestartSec = "30s"; # Retry every 30 seconds if the device isn't found
+ };
+ };
+}
diff --git a/roles/wallpaper.nix b/roles/wallpaper.nix
new file mode 100644
index 0000000..3cc4f91
--- /dev/null
+++ b/roles/wallpaper.nix
@@ -0,0 +1,23 @@
+{ pkgs, ... }:
+
+{
+ systemd.user.services.wallpaper = {
+ description = "wallpaper";
+ script = ''
+ ${pkgs.hyprland}/bin/hyprctl hyprpaper wallpaper ,$(find -L /etc/nixos/home/wallpapers -type f | shuf -n 1)
+ '';
+ serviceConfig = {
+ Type = "oneshot";
+ };
+ };
+
+ systemd.user.timers.wallpaper = {
+ wantedBy = [ "timers.target" ];
+ timerConfig = {
+ OnBootSec = "10m";
+ OnUnitActiveSec = "10m";
+ Unit = "wallpaper.service";
+ Persistent = true;
+ };
+ };
+}