temp commit

This commit is contained in:
mjallen18
2025-07-16 19:57:33 -05:00
parent 1a254d12c7
commit 6c7c76887b
89 changed files with 4356 additions and 2822 deletions

70
modules/nixos/amd/default.nix Executable file
View File

@@ -0,0 +1,70 @@
{
lib,
pkgs,
config,
...
}:
let
cfg = config.share.hardware.amd;
pkgsVersion = pkgs;#.unstable;
in
{
imports = [ ./options.nix ];
config = lib.mkIf cfg.enable {
boot = {
kernelModules = [ "nct6775" ];
kernelParams = [ (if cfg.enable then "amdgpu.ppfeaturemask=0xffffffff" else null) ];
};
# Configure programs
programs.corectrl = {
enable = cfg.corectrl.enable;
package = pkgsVersion.corectrl;
};
# Configure environment
environment = {
# Force radv
variables = {
AMD_VULKAN_ICD = "RADV";
STEAM_FORCE_DESKTOPUI_SCALING = "1.0";
GDK_SCALE = "1";
};
};
# Configure polkit
security.polkit = lib.mkIf cfg.corectrl.enablePolkit {
extraConfig = ''
polkit.addRule(function(action, subject) {
if ((action.id == "org.corectrl.helper.init" ||
action.id == "org.corectrl.helperkiller.init") &&
subject.local == true &&
subject.active == true &&
subject.isInGroup("${cfg.corectrl.polkitGroup}")) {
return polkit.Result.YES;
}
});
'';
};
# nixpkg is broken so need to manually define
systemd.services.lactd = lib.mkIf cfg.lact.enable {
description = "AMDGPU Control Daemon";
path = with pkgsVersion; [
bash
lact
];
script = ''
lact daemon
'';
wantedBy = [ "multi-user.target" ];
after = [ "multi-user.target" ];
};
# Configure environment
environment = {
systemPackages = with pkgsVersion; lib.mkIf cfg.lact.enable [ lact ];
};
};
}

27
modules/nixos/amd/options.nix Executable file
View File

@@ -0,0 +1,27 @@
{ lib, ... }:
with lib;
{
options.share.hardware.amd = {
enable = mkEnableOption "amd hardware config";
corectrl.enable = mkOption {
type = types.bool;
default = false;
};
corectrl.enablePolkit = mkOption {
type = types.bool;
default = false;
};
corectrl.polkitGroup = mkOption {
type = types.str;
default = "wheel";
};
lact.enable = mkOption {
type = types.bool;
default = false;
};
};
}

View File

@@ -0,0 +1,23 @@
{ lib, config, ... }:
with lib;
let
cfg = config.nas-apps.free-games-claimer;
in
{
imports = [ ./options.nix ];
config = mkIf cfg.enable {
virtualisation.oci-containers.containers."${cfg.name}" = {
autoStart = cfg.autoStart;
image = cfg.image;
ports = [ "${cfg.httpPort}:6080" ];
volumes = [ "${cfg.dataPath}:/fgc/data" ];
environmentFiles = [ config.sops.templates."fgc.env".path ];
environment = {
PUID = cfg.puid;
PGID = cfg.pgid;
TZ = cfg.timeZone;
};
};
};
}

View File

@@ -0,0 +1,47 @@
{ lib, ... }:
with lib;
{
options.nas-apps.free-games-claimer = {
enable = mkEnableOption "free-games-claimer docker service";
autoStart = mkOption {
type = types.bool;
default = true;
};
httpPort = mkOption {
type = types.str;
default = "6080";
};
name = mkOption {
type = types.str;
default = "free-games-claimer";
};
image = mkOption {
type = types.str;
default = "ghcr.io/vogler/free-games-claimer";
};
dataPath = mkOption {
type = types.str;
default = "/media/nas/ssd/nix-app-data/free-games-claimer";
};
puid = mkOption {
type = types.str;
default = "911";
};
pgid = mkOption {
type = types.str;
default = "1000";
};
timeZone = mkOption {
type = types.str;
default = "America/Chicago";
};
};
}

View File

@@ -0,0 +1,34 @@
{ lib, config, ... }:
with lib;
let
cfg = config.nas-apps.manyfold;
in
{
imports = [ ./options.nix ];
config = mkIf cfg.enable {
virtualisation.oci-containers.containers."${cfg.name}" = {
autoStart = cfg.autoStart;
image = cfg.image;
ports = [ "${cfg.httpPort}:3214" ];
extraOptions = [
"--cap-drop=ALL"
"--cap-add=CHOWN"
"--cap-add=DAC_OVERRIDE"
"--cap-add=SETUID"
"--cap-add=SETGID"
"--security-opt=no-new-privileges:true"
];
volumes = [
"${cfg.configPath}:/config"
"${cfg.dataPath}:/libraries"
];
environment = {
PUID = cfg.puid;
PGID = cfg.pgid;
TZ = cfg.timeZone;
};
environmentFiles = [ config.sops.secrets."jallen-nas/manyfold/secretkeybase".path ];
};
};
}

View File

@@ -0,0 +1,52 @@
{ lib, ... }:
with lib;
{
options.nas-apps.manyfold = {
enable = mkEnableOption "manyfold docker service";
autoStart = mkOption {
type = types.bool;
default = true;
};
httpPort = mkOption {
type = types.str;
default = "3214";
};
name = mkOption {
type = types.str;
default = "manyfold";
};
image = mkOption {
type = types.str;
default = "ghcr.io/manyfold3d/manyfold-solo";
};
configPath = mkOption {
type = types.str;
default = "/media/nas/ssd/nix-app-data/manyfold";
};
dataPath = mkOption {
type = types.str;
default = "/media/nas/main/3d_printer";
};
puid = mkOption {
type = types.str;
default = "911";
};
pgid = mkOption {
type = types.str;
default = "1000";
};
timeZone = mkOption {
type = types.str;
default = "America/Chicago";
};
};
}

View File

@@ -0,0 +1,26 @@
{ lib, config, ... }:
with lib;
let
cfg = config.nas-apps.mongodb;
in
{
imports = [ ./options.nix ];
config = mkIf cfg.enable {
virtualisation.oci-containers.containers."${cfg.name}" = {
autoStart = cfg.autoStart;
image = cfg.image;
ports = [ "${cfg.port}:27017" ];
volumes = [ "${cfg.configPath}:/data/db" ];
extraOptions = [ "--network-alias=mongo" ];
# environmentFiles = cfg.environmentFiles;
environment = {
PUID = cfg.puid;
PGID = cfg.pgid;
TZ = cfg.timeZone;
# MONGO_INITDB_ROOT_USERNAME = "";#cfg.databaseUser;
# MONGO_INITDB_ROOT_PASSWORD = "";#cfg.databasePassword; # get from env file
};
};
};
}

View File

@@ -0,0 +1,52 @@
{ lib, ... }:
with lib;
{
options.nas-apps.mongodb = {
enable = mkEnableOption "mongodb docker service";
autoStart = mkOption {
type = types.bool;
default = true;
};
port = mkOption {
type = types.str;
default = "27017";
};
name = mkOption {
type = types.str;
default = "mongo";
};
image = mkOption {
type = types.str;
default = "mongo";
};
configPath = mkOption {
type = types.str;
default = "/media/nas/ssd/mongodb";
};
puid = mkOption {
type = types.str;
default = "911";
};
pgid = mkOption {
type = types.str;
default = "1000";
};
timeZone = mkOption {
type = types.str;
default = "America/Chicago";
};
environmentFiles = mkOption {
type = with types; listOf path;
default = [ ];
};
};
}

View File

@@ -0,0 +1,42 @@
{ lib, config, ... }:
with lib;
let
cfg = config.nas-apps.tdarr;
in
{
imports = [ ./options.nix ];
config = mkIf cfg.enable {
virtualisation.oci-containers.containers.${cfg.name} = {
autoStart = true;
image = cfg.image;
extraOptions = [ "--device=nvidia.com/gpu=0" ];
volumes = [
"${cfg.configPath}:/app/configs"
"${cfg.serverPath}:/app/server"
"${cfg.logPath}:/app/logs"
"${cfg.transcodePath}:/temp"
"${cfg.moviesPath}:/data/movies"
"${cfg.tvPath}:/data/tv"
];
ports = [
"${cfg.serverPort}:8266"
"${cfg.webUIPort}:8265"
];
environment = {
serverPort = "8266";
webUIPort = "8265";
internalNode = "true";
inContainer = "true";
ffmpegVersion = "6";
nodeName = "tdarr node";
NVIDIA_VISIBLE_DEVICES = "all";
NVIDIA_DRIVER_CAPABILITIES = "all";
PUID = cfg.puid;
PGID = cfg.pgid;
TZ = cfg.timeZone;
};
};
};
}

View File

@@ -0,0 +1,77 @@
{ lib, ... }:
with lib;
{
options.nas-apps.tdarr = {
enable = mkEnableOption "tdarr docker service";
autoStart = mkOption {
type = types.bool;
default = true;
};
serverPort = mkOption {
type = types.str;
default = "8266";
};
webUIPort = mkOption {
type = types.str;
default = "8265";
};
name = mkOption {
type = types.str;
default = "tdarr";
};
image = mkOption {
type = types.str;
default = "ghcr.io/haveagitgat/tdarr";
};
configPath = mkOption {
type = types.str;
default = "/media/nas/ssd/nix-app-data/tdarr/config";
};
serverPath = mkOption {
type = types.str;
default = "/media/nas/ssd/nix-app-data/tdarr/server";
};
logPath = mkOption {
type = types.str;
default = "/media/nas/ssd/nix-app-data/tdarr/logs";
};
transcodePath = mkOption {
type = types.str;
default = "/media/nas/ssd/nix-app-data/tdarr/transcode";
};
moviesPath = mkOption {
type = types.str;
default = "/media/nas/main/movies";
};
tvPath = mkOption {
type = types.str;
default = "/media/nas/main/tv";
};
puid = mkOption {
type = types.str;
default = "911";
};
pgid = mkOption {
type = types.str;
default = "1000";
};
timeZone = mkOption {
type = types.str;
default = "America/Chicago";
};
};
}

View File

@@ -0,0 +1,41 @@
{ lib, config, ... }:
with lib;
let
cfg = config.nas-apps.your_spotify;
in
{
imports = [ ./options.nix ];
config = mkIf cfg.enable {
virtualisation.oci-containers.containers."${cfg.name}-server" = {
autoStart = true;
image = cfg.imageServer;
volumes = [ "${cfg.configPath}:/root/.your-spotify" ];
ports = [ "${cfg.portServer}:8080" ];
dependsOn = [ "mongo" ];
environment = {
PUID = cfg.puid;
PGID = cfg.pgid;
TZ = cfg.timeZone;
API_ENDPOINT = "https://your-spotify-server.mjallen.dev";
CLIENT_ENDPOINT = "https://your-spotify.mjallen.dev";
SPOTIFY_PUBLIC = "e270589d72a6494680a17d325af8670d";
SPOTIFY_SECRET = "423cb7b69fe8486e89eccd01e0c22924";
MONGO_ENDPOINT = "mongodb://10.0.1.3:27017";
};
};
virtualisation.oci-containers.containers."${cfg.name}-web" = {
autoStart = true;
image = cfg.imageWeb;
ports = [ "${cfg.portWeb}:3000" ];
environment = {
PUID = cfg.puid;
PGID = cfg.pgid;
TZ = cfg.timeZone;
API_ENDPOINT = "https://your-spotify-server.mjallen.dev";
};
};
};
}

View File

@@ -0,0 +1,57 @@
{ lib, ... }:
with lib;
{
options.nas-apps.your_spotify = {
enable = mkEnableOption "your_spotify docker service";
autoStart = mkOption {
type = types.bool;
default = true;
};
portServer = mkOption {
type = types.str;
default = "7777";
};
portWeb = mkOption {
type = types.str;
default = "7778";
};
name = mkOption {
type = types.str;
default = "your_spotify";
};
imageServer = mkOption {
type = types.str;
default = "yooooomi/your_spotify_server";
};
imageWeb = mkOption {
type = types.str;
default = "yooooomi/your_spotify_client";
};
configPath = mkOption {
type = types.str;
default = "/media/nas/ssd/nix-app-data/your_spotify";
};
puid = mkOption {
type = types.str;
default = "911";
};
pgid = mkOption {
type = types.str;
default = "1000";
};
timeZone = mkOption {
type = types.str;
default = "America/Chicago";
};
};
}

View File

@@ -0,0 +1,7 @@
{ ... }:
{
services = {
desktopManager.cosmic.enable = true;
displayManager.cosmic-greeter.enable = true;
};
}

View File

@@ -0,0 +1,7 @@
{ ... }:
{
specialisation.cosmic.configuration = {
imports = [ ./default.nix ];
environment.etc."specialisation".text = "cosmic";
};
}

View File

@@ -0,0 +1,23 @@
{ lib, pkgs, ... }:
{
services = {
# Enable Desktop Environment.
desktopManager.gnome.enable = true;
# Enable Desktop Environment.
displayManager = {
gdm.enable = lib.mkDefault true;
gdm.wayland = lib.mkDefault true;
};
gnome.gnome-remote-desktop.enable = true;
};
xdg.portal.extraPortals = [ pkgs.xdg-desktop-portal-gtk ];
programs = {
kdeconnect = {
enable = true;
package = pkgs.gnomeExtensions.gsconnect;
};
};
}

View File

@@ -0,0 +1,87 @@
{ ... }:
let
rootDisk = "/dev/nvme0n1";
in
{
disko.devices.disk.main.imageSize = "32G";
disko.devices = {
nodev."/" = {
fsType = "tmpfs";
mountOptions = [
"mode=755"
"defaults"
"size=25%"
];
};
# root disk setup
disk.main = {
type = "disk";
device = rootDisk;
content = {
type = "gpt";
# specify partitions
partitions = {
# /boot
ESP = {
priority = 1;
name = "ESP";
start = "1M";
end = "1G";
type = "EF00";
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot";
mountOptions = [ "umask=0077" ];
};
};
root = {
name = "btrfs-root";
size = "100%";
content = {
type = "btrfs";
extraArgs = [ "-f" ]; # Override existing partition
# Subvolumes must set a mountpoint in order to be mounted,
# unless their parent is mounted
subvolumes = {
"home" = {
mountOptions = [ "compress=zstd" ];
mountpoint = "/home";
};
"root" = {
mountOptions = [
"compress=zstd"
"noatime"
];
mountpoint = "/root";
};
"nix" = {
mountOptions = [
"compress=zstd"
"noatime"
];
mountpoint = "/nix";
};
"etc" = {
mountOptions = [
"compress=zstd"
"noatime"
];
mountpoint = "/etc";
};
"log" = {
mountOptions = [
"compress=zstd"
"noatime"
];
mountpoint = "/var/log";
};
};
};
};
};
};
};
};
}

View File

@@ -0,0 +1,102 @@
{ ... }:
let
rootDisk = "/dev/nvme0n1";
in
{
disko.devices.disk.main.imageSize = "15G";
disko.devices = {
nodev."/" = {
fsType = "tmpfs";
mountOptions = [
"mode=755"
"defaults"
"size=2G"
];
};
# root disk setup
disk.main = {
type = "disk";
device = rootDisk;
content = {
type = "gpt";
# specify partitions
partitions = {
# /boot/firmware
FIRMWARE = {
priority = 1;
name = "FIRMWARE";
start = "1M";
end = "1G";
type = "0700";
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot/firmware";
mountOptions = [ "umask=0077" ];
};
};
# /boot
ESP = {
priority = 2;
name = "ESP";
# start = "1G";
# end = "2G";
size = "1G";
type = "EF00";
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot";
mountOptions = [ "umask=0077" ];
};
};
root = {
name = "btrfs-root";
size = "100%";
content = {
type = "btrfs";
extraArgs = [ "-f" ]; # Override existing partition
# Subvolumes must set a mountpoint in order to be mounted,
# unless their parent is mounted
subvolumes = {
"home" = {
mountOptions = [ "compress=zstd" ];
mountpoint = "/home";
};
"root" = {
mountOptions = [
"compress=zstd"
"noatime"
];
mountpoint = "/root";
};
"nix" = {
mountOptions = [
"compress=zstd"
"noatime"
];
mountpoint = "/nix";
};
"etc" = {
mountOptions = [
"compress=zstd"
"noatime"
];
mountpoint = "/etc";
};
"log" = {
mountOptions = [
"compress=zstd"
"noatime"
];
mountpoint = "/var/log";
};
};
};
};
};
};
};
};
}

View File

@@ -0,0 +1,75 @@
{ lib, config, pkgs, ... }:
let
cfg = config.share.gaming;
pkgsVersion = pkgs; #.unstable;
in
{
imports = [ ./options.nix ];
config = lib.mkIf cfg.enable {
# Network option required using sysctl to let Ubisoft Connect work as of 7-12-2023
boot.kernel.sysctl."net.ipv4.tcp_mtu_probing" = 1;
# Configure programs
programs.steam = {
enable = true;
# Open ports in the firewall for Steam Remote Play
remotePlay.openFirewall = true;
# Open ports in the firewall for Source Dedicated Server
dedicatedServer.openFirewall = true;
extraCompatPackages = with pkgsVersion; [ proton-ge-bin];
gamescopeSession = {
enable = true;
args = [
"-f"
"-H 2160"
"-W 3840"
"-r 240"
"--hdr-enabled"
"--adaptive-sync"
];
};
}; # "gamescope -f -H 2160 -W 3840 -r 240 --adaptive-sync --hdr-enabled
programs = {
alvr = {
enable = true;
openFirewall = true;
};
gamescope = {
enable = true;
capSysNice = true;
};
gamemode.enable = true;
};
# Hardware configs
hardware = {
# Xbox controllers
xpadneo.enable = false;
# Steam udev rules for remote play
steam-hardware.enable = true;
};
# Configure nixpkgs
nixpkgs.config.packageOverrides = pkgs: {
steam = pkgs.steam.override {
extraPkgs =
pkgs: with pkgsVersion; [
xorg.libXcursor
xorg.libXi
xorg.libXinerama
xorg.libXScrnSaver
libpng
libpulseaudio
libvorbis
stdenv.cc.cc.lib
libkrb5
keyutils
];
};
};
};
}

View File

@@ -0,0 +1,7 @@
{ lib, ... }:
with lib;
{
options.share.gaming = {
enable = mkEnableOption "enable gaming stuffs";
};
}

View File

@@ -0,0 +1,236 @@
- id: '1740678838632'
alias: Bedroom Light Switch
description: ''
triggers:
- domain: mqtt
device_id: 8b3a5a5b6faaba744c70ee940446a8af
type: action
subtype: on-press
trigger: device
id: on press
- domain: mqtt
device_id: 8b3a5a5b6faaba744c70ee940446a8af
type: action
subtype: off-press
trigger: device
id: off press
- domain: mqtt
device_id: 8b3a5a5b6faaba744c70ee940446a8af
type: action
subtype: up-press
trigger: device
id: up press
- domain: mqtt
device_id: 8b3a5a5b6faaba744c70ee940446a8af
type: action
subtype: down-press
trigger: device
id: down press
conditions: []
actions:
- choose:
- conditions:
- condition: trigger
id:
- on press
sequence:
- action: light.turn_on
metadata: {}
data:
transition: 2
brightness_pct: 100
kelvin: 6004
target:
entity_id: light.bedroom_lights
- conditions:
- condition: trigger
id:
- off press
sequence:
- action: light.turn_off
metadata: {}
data:
transition: 2
target:
entity_id: light.bedroom_lights
- conditions:
- condition: trigger
id:
- up press
sequence:
- action: light.turn_on
metadata: {}
data:
brightness_step_pct: 10
target:
entity_id: light.bedroom_lights
- conditions:
- condition: trigger
id:
- down press
sequence:
- action: light.turn_on
metadata: {}
data:
brightness_step_pct: -10
target:
entity_id: light.bedroom_lights
mode: single
- id: '1740697291423'
alias: Living Rooom Lights
description: ''
triggers:
- domain: mqtt
device_id: b4fb325dfe68d4f80391417998f35843
type: action
subtype: on-press
trigger: device
id: on press
- domain: mqtt
device_id: b4fb325dfe68d4f80391417998f35843
type: action
subtype: off-press
trigger: device
id: off press
- domain: mqtt
device_id: b4fb325dfe68d4f80391417998f35843
type: action
subtype: up-press
trigger: device
id: up press
- domain: mqtt
device_id: b4fb325dfe68d4f80391417998f35843
type: action
subtype: down-press
trigger: device
id: down press
- domain: mqtt
device_id: b4fb325dfe68d4f80391417998f35843
type: action
subtype: on-hold
trigger: device
id: on-hold
conditions: []
actions:
- choose:
- conditions:
- condition: trigger
id:
- on press
sequence:
- action: light.turn_on
metadata: {}
data:
transition: 2
brightness_pct: 100
kelvin: 6004
target:
entity_id:
- light.living_room_lights
- conditions:
- condition: trigger
id:
- off press
sequence:
- action: light.turn_off
metadata: {}
data:
transition: 2
target:
entity_id:
- light.living_room_lights
- conditions:
- condition: trigger
id:
- up press
sequence:
- action: light.turn_on
metadata: {}
data:
brightness_step_pct: 10
target:
entity_id: light.living_room_lights
- conditions:
- condition: trigger
id:
- down press
sequence:
- action: light.turn_on
metadata: {}
data:
brightness_step_pct: -10
target:
entity_id: light.living_room_light_1
- conditions:
- condition: trigger
id:
- on-hold
sequence:
- action: light.turn_on
metadata: {}
data:
transition: 0
brightness_pct: 100
rgb_color:
- 224
- 27
- 36
target:
entity_id: light.living_room_lights
mode: single
- id: '1741048414771'
alias: Front Closet
description: ''
triggers:
- type: present
device_id: c6519ea1e715f397dbbf7b73452f9e49
entity_id: c3a7b8892b8b372d2c40556e770ddc68
domain: binary_sensor
trigger: device
for:
hours: 0
minutes: 0
seconds: 0
id: present
- type: not_present
device_id: c6519ea1e715f397dbbf7b73452f9e49
entity_id: c3a7b8892b8b372d2c40556e770ddc68
domain: binary_sensor
trigger: device
for:
hours: 0
minutes: 0
seconds: 5
id: not
conditions: []
actions:
- choose:
- conditions:
- condition: trigger
id:
- present
sequence:
- action: light.turn_on
metadata: {}
data:
transition: 2
brightness_pct: 100
kelvin: 6010
target:
entity_id:
- light.front_closet_light_1
- light.front_closet_light_2
- conditions:
- condition: trigger
id:
- not
sequence:
- action: light.turn_off
metadata: {}
data:
transition: 2
target:
entity_id:
- light.front_closet_light_1
- light.front_closet_light_2
mode: single

View File

@@ -0,0 +1,576 @@
- id: '1692388103102'
alias: Weekly Backup
description: Create a full backup every Sunday at 3 am and store it on the NAS
trigger:
- platform: time
at: 03:00:00
condition:
- condition: time
weekday:
- sun
action:
- service: hassio.backup_full
data:
compressed: true
mode: single
- id: '1692389901297'
alias: Livingroom Lights
description: ''
trigger:
- platform: device
domain: mqtt
device_id: 37d42431de65199af00220b43dae04c1
type: action
subtype: on_press
id: 'on'
- platform: device
domain: mqtt
device_id: 37d42431de65199af00220b43dae04c1
type: action
subtype: off_press
id: 'off'
- platform: device
domain: mqtt
device_id: 37d42431de65199af00220b43dae04c1
type: action
subtype: up_press
id: up
- platform: device
domain: mqtt
device_id: 37d42431de65199af00220b43dae04c1
type: action
subtype: down_press
id: down
- platform: device
domain: mqtt
device_id: 37d42431de65199af00220b43dae04c1
type: action
subtype: on_hold
id: hold
condition: []
action:
- choose:
- conditions:
- condition: trigger
id:
- 'on'
sequence:
- data:
brightness_pct: 100
color_temp_kelvin: 5000
transition: 1
target:
entity_id: light.livingroom_lights
action: light.turn_on
- conditions:
- condition: trigger
id:
- 'off'
sequence:
- data:
transition: 1
target:
entity_id: light.livingroom_lights
action: light.turn_off
- conditions:
- condition: trigger
id:
- hold
sequence:
- data:
brightness_pct: 100
rgb_color:
- 255
- 38
- 0
transition: 1
target:
entity_id: light.livingroom_lights
action: light.turn_on
- conditions:
- condition: trigger
id:
- dim up
sequence:
- data:
brightness_step_pct: 20
target:
entity_id: light.livingroom_lights
action: light.turn_on
- conditions:
- condition: trigger
id:
- dim down
sequence:
- data:
brightness_step_pct: -20
target:
entity_id: light.livingroom_lights
action: light.turn_on
mode: single
- id: '1692390365798'
alias: Bedroom Lights
description: ''
triggers:
- domain: mqtt
device_id: a492c0abb8f14e0888df08101f77f484
type: action
subtype: off_press
id: 'off'
trigger: device
- domain: mqtt
device_id: a492c0abb8f14e0888df08101f77f484
type: action
subtype: on_press
id: 'on'
trigger: device
- domain: mqtt
device_id: a492c0abb8f14e0888df08101f77f484
type: action
subtype: up_press
id: up
trigger: device
- domain: mqtt
device_id: a492c0abb8f14e0888df08101f77f484
type: action
subtype: down_press
id: down
trigger: device
- domain: mqtt
device_id: a492c0abb8f14e0888df08101f77f484
type: action
subtype: on_hold
id: hold on
trigger: device
conditions: []
actions:
- choose:
- conditions:
- condition: trigger
id:
- 'on'
sequence:
- data:
brightness_pct: 100
color_temp_kelvin: 5000
transition: 1
target:
entity_id: light.bedroom_lights
action: light.turn_on
- conditions:
- condition: trigger
id:
- 'off'
sequence:
- data:
transition: 1
target:
entity_id:
- light.bedroom_lights
action: light.turn_off
- conditions:
- condition: trigger
id:
- up
sequence:
- device_id: 171fa001578683249ff26f2d85817fef
domain: light
entity_id: 55d41329665f60a55a732c5bbececd22
type: brightness_increase
- device_id: c92fea3d569ca668e6617a189f917a28
domain: light
entity_id: 0c8630c2b37ae9615f9cf815aaebf40f
type: brightness_increase
- conditions:
- condition: trigger
id:
- down
sequence:
- device_id: 171fa001578683249ff26f2d85817fef
domain: light
entity_id: 55d41329665f60a55a732c5bbececd22
type: brightness_decrease
- device_id: c92fea3d569ca668e6617a189f917a28
domain: light
entity_id: 0c8630c2b37ae9615f9cf815aaebf40f
type: brightness_decrease
- conditions:
- condition: trigger
id:
- hold on
sequence:
- metadata: {}
data:
rgb_color:
- 255
- 0
- 0
brightness_pct: 100
target:
entity_id: light.bedroom_lights
action: light.turn_on
mode: single
- id: '1694441037420'
alias: Air Purifier Schedule
description: ''
trigger:
- platform: time
at: 07:00:00
id: fan off
- platform: time
at: '23:00:00'
id: fan on
condition: []
action:
- choose:
- conditions:
- condition: trigger
id:
- fan on
sequence:
- service: fan.set_percentage
data:
percentage: 100
target:
entity_id: fan.bedroom_air_purifier
- conditions:
- condition: trigger
id:
- fan off
sequence:
- service: fan.set_preset_mode
data:
preset_mode: auto
target:
entity_id: fan.bedroom_air_purifier
mode: single
- id: '1705949582146'
alias: Ice Maker Power Schedule
description: ''
trigger:
- platform: time_pattern
hours: '*'
minutes: '0'
seconds: '0'
condition: []
action:
- type: toggle
device_id: 41c66532e23aadc4c6ac95e520e5d345
entity_id: bd17ac75a91e62ed7e6b148cfe33d43d
domain: switch
- alias: Set Ice Maker Light to Dim
device_id: 41c66532e23aadc4c6ac95e520e5d345
domain: select
entity_id: 8f4f90c62b00df9008d14f7ce8967199
type: select_option
option: 'On'
mode: single
- id: '1708978401738'
alias: Soundbar
description: ''
trigger: []
condition: []
action:
- service: media_player.turn_on
metadata: {}
data: {}
target:
entity_id: media_player.soundbar
- service: media_player.select_source
metadata: {}
data:
source: wifi
target:
entity_id: media_player.soundbar
- service: media_player.play_media
metadata: {}
data:
media_content_id: media-source://radio_browser/2eff3a1f-b821-4267-9f37-f8d7e72061e4
media_content_type: audio/mpeg
target:
entity_id: media_player.soundbar
mode: single
- id: '1711147285926'
alias: Grow Light Schedule
description: ''
trigger:
- platform: time
at: 07:00:00
id: day
- platform: time
at: '20:00:00'
id: night
condition: []
action:
- choose:
- conditions:
- condition: trigger
id:
- day
sequence:
- service: switch.turn_on
metadata: {}
data: {}
target:
entity_id: switch.grow_lights
- conditions:
- condition: trigger
id:
- night
sequence:
- service: switch.turn_off
metadata: {}
data: {}
target:
entity_id: switch.grow_lights
mode: single
- id: '1723142554607'
alias: Restart Luci's Box
description: for some reason this box sucks and needs to get reboot periodically
trigger:
- platform: time_pattern
hours: '*'
condition: []
action:
- type: turn_off
device_id: e7f8974c31567dddbbffb036fe8381bc
entity_id: e1e71e4acdfcbb6c4afdc174807ad8be
domain: switch
- delay:
hours: 0
minutes: 0
seconds: 1
milliseconds: 0
- type: turn_on
device_id: e7f8974c31567dddbbffb036fe8381bc
entity_id: e1e71e4acdfcbb6c4afdc174807ad8be
domain: switch
- type: turn_on
device_id: d5eb3c182a1ef2a231b94b09c26aed45
entity_id: 7106df7ebde274ac4bc2b197d5c45bea
domain: fan
- device_id: d5eb3c182a1ef2a231b94b09c26aed45
domain: number
entity_id: 59a7cd3cb2883bf6002f789c2ff4824c
type: set_value
value: 3
mode: single
- id: '1724707092916'
alias: HASS Updates
description: ''
use_blueprint:
path: edwardtfn/auto_update_scheduled.yaml
input:
schedule_entity: schedule.updates
restart_bool: true
- id: '1724707291994'
alias: IOT Battery Checker
description: ''
use_blueprint:
path: sbyx/low-battery-level-detection-notification-for-all-battery-sensors.yaml
input:
exclude:
entity_id: []
device_id:
- 66e9cee67a740e8925dae5fc9ce940f0
- df76e3a3e48b49e13bd3006350826740
actions:
- action: notify.persistent_notification
metadata: {}
data:
message: Device Battery Low
- id: '1729708621620'
alias: Closet Lights
description: ''
triggers:
- type: present
device_id: 0924cbdcd24416e768caa52301db59f7
entity_id: e9f0acef50550033cd96155bd501b7c3
domain: binary_sensor
trigger: device
for:
hours: 0
minutes: 0
seconds: 0
id: Present
- type: not_present
device_id: 0924cbdcd24416e768caa52301db59f7
entity_id: e9f0acef50550033cd96155bd501b7c3
domain: binary_sensor
trigger: device
for:
hours: 0
minutes: 0
seconds: 0
id: empty
conditions: []
actions:
- choose:
- conditions:
- condition: trigger
id:
- Present
sequence:
- action: light.turn_on
metadata: {}
data:
transition: 3
brightness_pct: 100
kelvin: 5008
target:
device_id:
- e25128ac8fcf62af66a039cde3104760
- ddcfd5ea4fc5f5a88e18325b01c615db
- conditions:
- condition: trigger
id:
- empty
sequence:
- action: light.turn_off
metadata: {}
data:
transition: 3
target:
device_id:
- e25128ac8fcf62af66a039cde3104760
- ddcfd5ea4fc5f5a88e18325b01c615db
mode: single
- id: '1729881464325'
alias: Bedroom Closet
description: ''
triggers:
- type: present
device_id: 28e7f211c72409fe244183219abf6ffa
entity_id: aa474f323868586cef62070654f36936
domain: binary_sensor
trigger: device
id: Present
- type: not_present
device_id: 28e7f211c72409fe244183219abf6ffa
entity_id: aa474f323868586cef62070654f36936
domain: binary_sensor
trigger: device
id: empty
conditions: []
actions:
- choose:
- conditions:
- condition: trigger
id:
- Present
sequence:
- type: turn_on
device_id: f5936d6143b7927433e9c0430c79acab
entity_id: f6ec42c9db2c191866a335a346b1ec44
domain: switch
- conditions:
- condition: trigger
id:
- empty
sequence:
- type: turn_off
device_id: f5936d6143b7927433e9c0430c79acab
entity_id: f6ec42c9db2c191866a335a346b1ec44
domain: switch
mode: single
- id: '1740179328446'
alias: Living Room Lights
description: ''
triggers:
- domain: mqtt
device_id: f7482a462dc7cc05b4ceaa0d882dc469
type: action
subtype: off_press
trigger: device
id: 'off'
- domain: mqtt
device_id: f7482a462dc7cc05b4ceaa0d882dc469
type: action
subtype: on_press
trigger: device
id: 'on'
- domain: mqtt
device_id: f7482a462dc7cc05b4ceaa0d882dc469
type: action
subtype: up_press
trigger: device
id: up
- domain: mqtt
device_id: f7482a462dc7cc05b4ceaa0d882dc469
type: action
subtype: down_press
trigger: device
id: down
- domain: mqtt
device_id: f7482a462dc7cc05b4ceaa0d882dc469
type: action
subtype: on_hold
trigger: device
id: hold on
conditions: []
actions:
- choose:
- conditions:
- condition: trigger
id:
- 'on'
sequence:
- data:
brightness_pct: 100
color_temp_kelvin: 5000
transition: 1
action: light.turn_on
target:
entity_id: light.livingroom_lights
- conditions:
- condition: trigger
id:
- 'off'
sequence:
- data:
transition: 1
action: light.turn_off
target:
entity_id: light.livingroom_lights
- conditions:
- condition: trigger
id:
- up
sequence:
- device_id: 8bc2033b03d5a474ca3204c5ca53e308
domain: light
entity_id: 4a3cc9043ff985e9271683e1916bd9e1
type: brightness_increase
- device_id: 8f4f51aed9b3b4284f520af25358efd9
domain: light
entity_id: f45e74498c4b6bae65aaf5adf67e29d6
type: brightness_increase
- conditions:
- condition: trigger
id:
- down
sequence:
- device_id: 8bc2033b03d5a474ca3204c5ca53e308
domain: light
entity_id: 4a3cc9043ff985e9271683e1916bd9e1
type: brightness_decrease
- device_id: 8bc2033b03d5a474ca3204c5ca53e308
domain: light
entity_id: 4a3cc9043ff985e9271683e1916bd9e1
type: brightness_decrease
- conditions:
- condition: trigger
id:
- hold on
sequence:
- metadata: {}
data:
rgb_color:
- 255
- 0
- 0
brightness_pct: 100
action: light.turn_on
target:
entity_id: light.livingroom_lights
mode: single

View File

@@ -0,0 +1,47 @@
{ pkgs, ... }:
let
uart-wifi = pkgs.python3Packages.buildPythonPackage rec {
pname = "uart-wifi";
version = "0.2.1";
format = "pyproject";
src = pkgs.fetchPypi {
inherit pname version;
sha256 = "sha256-yquZ5V8f+EqetCf0nc9WlhHhnHkOASYRuYvqEIMc5HI=";
};
buildInputs = with pkgs.python3Packages; [ setuptools ];
doCheck = false; # no tests in the PyPI tarball
};
ha-anycubic = pkgs.buildHomeAssistantComponent rec {
owner = "adamoutler";
domain = "anycubic_wifi";
version = "HACS-10";
src = pkgs.fetchFromGitHub {
owner = owner;
repo = "anycubic-homeassistant";
rev = version;
hash = "sha256-TfZadwgdEJR11MaL+nfIgEYld3trWg3v6lOHSoxQ98Q=";
};
# PYTHONPATH = [ "${src}/uart-wifi" ];
propagatedBuildInputs = [
uart-wifi
];
meta = {
changelog = "https://github.com/adamoutler/anycubic-homeassistant/releases/tag/${version}";
description = "This is a library to provide support for Mono X Printers.";
homepage = "https://github.com/adamoutler/anycubic-homeassistant";
maintainers = [ ];
};
};
in
{
services.home-assistant.customComponents = [
ha-anycubic
];
}

View File

@@ -0,0 +1,31 @@
{ pkgs, ... }:
let
ha-bambulab = pkgs.buildHomeAssistantComponent rec {
owner = "greghesp";
domain = "bambu_lab";
version = "v2.1.27";
src = pkgs.fetchFromGitHub {
owner = owner;
repo = "ha-bambulab";
rev = version;
hash = "sha256-zHPXPYsHrJXOnSqllZqDrxGZDDqyXllC3XEGZRJil0Q=";
};
propagatedBuildInputs = with pkgs.python3Packages; [
beautifulsoup4
];
meta = {
changelog = "https://github.com/greghesp/ha-bambulab/releases/tag/${version}";
description = "A Home Assistant Integration for Bambu Lab printers.";
homepage = "https://github.com/greghesp/ha-bambulab";
maintainers = [ ];
};
};
in
{
services.home-assistant.customComponents = [
ha-bambulab
];
}

View File

@@ -0,0 +1,14 @@
{ ... }:
{
imports = [
./anycubic.nix
./bambulab.nix
./gehome.nix
./icloud3.nix
./mail-and-packages.nix
./nanokvm.nix
./overseerr.nix
./petlibro.nix
./wyzeapi.nix
];
}

View File

@@ -0,0 +1,54 @@
{ pkgs, ... }:
let
magicattr_cust = pkgs.python3Packages.buildPythonPackage rec {
pname = "magicattr";
version = "0.1.6";
format = "setuptools";
src = pkgs.fetchFromGitHub {
owner = "frmdstryr";
repo = pname;
rev = "master";
sha256 = "sha256-FJtWU5AuunZbdlndGdfD1c9/0s7oRdoTi202pWjuAd8=";
};
buildInputs = with pkgs.python3Packages; [ setuptools ];
doCheck = false;
};
ha-gehome = pkgs.buildHomeAssistantComponent rec {
owner = "simbaja";
domain = "ge_home";
version = "v2025.5.0";
src = pkgs.fetchFromGitHub {
owner = owner;
repo = "ha_gehome";
rev = version;
hash = "sha256-NlUkM70yvBeC5s7S5BkNxIC2GztfEq8xYrQZr4pkaGU=";
};
propagatedBuildInputs = with pkgs.python3Packages; [
gehomesdk
magicattr_cust
slixmpp
];
postPatch = ''
substituteInPlace custom_components/ge_home/manifest.json \
--replace '"slixmpp==1.8.3"' '"slixmpp>=1.8.3"'
'';
meta = {
changelog = "https://github.com/simbaja/ha_gehome/releases/tag/${version}";
description = "Integration for GE WiFi-enabled appliances into Home Assistant.";
homepage = "https://github.com/simbaja/ha_gehome";
maintainers = [ ];
};
};
in
{
services.home-assistant.customComponents = [
ha-gehome
];
}

View File

@@ -0,0 +1,31 @@
{ pkgs, ... }:
let
ha-icloud3 = pkgs.buildHomeAssistantComponent rec {
owner = "gcobb321";
domain = "icloud3";
version = "3.2.2.3";
src = pkgs.fetchFromGitHub {
owner = owner;
repo = "icloud3";
rev = "v.${version}";
hash = "sha256-OjXioS73jE/U2YeKYf84QnStdQj3Seid4hJ2TH6z13M=";
};
propagatedBuildInputs = with pkgs.python3Packages; [
srp
];
meta = {
changelog = "https://github.com/gcobb321/icloud3/releases/tag/${version}";
description = "Cloud3 is a device tracker custom component that tracks your iPhones, iPads and Apple Watches. Devices in the Family Sharing List and the HA Mobile App Integration are trackable.";
homepage = "https://github.com/gcobb321/icloud3";
maintainers = [ ];
};
};
in
{
services.home-assistant.customComponents = [
ha-icloud3
];
}

View File

@@ -0,0 +1,39 @@
{ pkgs, ... }:
let
ha-mail-and-packages = pkgs.buildHomeAssistantComponent rec {
owner = "moralmunky";
domain = "mail_and_packages";
version = "0.4.2";
src = pkgs.fetchFromGitHub {
owner = owner;
repo = "Home-Assistant-Mail-And-Packages";
rev = version;
hash = "sha256-5LBTlRlkSUx8DOY+F7UvUs4dzjZKdBdgnDUdK6DBdew=";
};
propagatedBuildInputs = with pkgs.python3Packages; [
beautifulsoup4
dateparser
pillow
];
postPatch = ''
substituteInPlace custom_components/mail_and_packages/const.py \
--replace 'DEFAULT_PATH = "/var/lib/homeassistant/images/"' 'DEFAULT_PATH = "/var/lib/homeassistant/images/"'
--replace 'DEFAULT_CUSTOM_IMG_FILE = "/var/lib/homeassistant/mail_none.gif"' 'DEFAULT_CUSTOM_IMG_FILE = "/var/lib/homeassistant/mail_none.gif"'
'';
meta = {
changelog = "https://github.com/moralmunky/Home-Assistant-Mail-And-Packages/releases/tag/${version}";
description = "The Mail and Packages integration creates sensors for supported shippers to show a snapshot of mail and packages that are scheduled to be delivered the current day.";
homepage = "https://github.com/moralmunky/Home-Assistant-Mail-And-Packages";
maintainers = [ ];
};
};
in
{
services.home-assistant.customComponents = [
ha-mail-and-packages
];
}

View File

@@ -0,0 +1,59 @@
{ pkgs, ... }:
let
python-nanokvm = pkgs.python3Packages.buildPythonPackage rec {
pname = "python-nanokvm";
version = "v0.0.3";
format = "pyproject";
src = pkgs.fetchFromGitHub {
owner = "puddly";
repo = pname;
rev = version;
sha256 = "sha256-jBBd+O3S/4AlxAhrF9j9Bi5vMKZNk0M17ok9JzcI8F8=";
};
buildInputs = with pkgs.python3Packages; [
setuptools
setuptools-git-versioning
];
nativeBuildInputs = with pkgs.python3Packages; [
aiohttp
cryptography
yarl
pillow
pydantic
];
doCheck = false;
};
ha-nanokvm = pkgs.buildHomeAssistantComponent rec {
owner = "Wouter0100";
domain = "nanokvm";
version = "v0.0.1";
src = pkgs.fetchFromGitHub {
owner = owner;
repo = "homeassistant-nanokvm";
rev = "663f9710dfea109f0bb0417df5828b8d639e70c4";
hash = "sha256-6rTEOshNCe0x4iEHljqY/6p2TK1HasgNycRHkmo2Hhw=";
};
propagatedBuildInputs = [
python-nanokvm
];
meta = {
changelog = "https://github.com/Wouter0100/homeassistant-nanokvm/releases/tag/${version}";
description = "This integration allows you to control and monitor your Sipeed NanoKVM device from Home Assistant.";
homepage = "https://github.com/Wouter0100/homeassistant-nanokvm";
maintainers = [ ];
};
};
in
{
services.home-assistant.customComponents = [
ha-nanokvm
];
}

View File

@@ -0,0 +1,47 @@
{ pkgs, ... }:
let
pyoverseerr = pkgs.python3Packages.buildPythonPackage rec {
pname = "pyoverseerr";
version = "0.1.40";
format = "setuptools";
src = pkgs.fetchFromGitHub {
owner = "vaparr";
repo = pname;
rev = "master";
sha256 = "sha256-sWYe6EV/IO/tGGXcnKiebb47eidIj0xnM/aZUfdZXyY=";
};
buildInputs = with pkgs.python3Packages; [ setuptools ];
doCheck = false; # no tests in the PyPI tarball
};
ha-overseerr = pkgs.buildHomeAssistantComponent rec {
owner = "vaparr";
domain = "overseerr";
version = "0.1.42";
src = pkgs.fetchFromGitHub {
owner = owner;
repo = "ha-overseerr";
rev = version;
hash = "sha256-UvUowCgfay9aRV+iC/AQ9vvJzhGZbH+/1kVjxPFBKcI=";
};
propagatedBuildInputs = [
pyoverseerr
];
meta = {
changelog = "https://github.com/vaparr/ha-overseerr/releases/tag/${version}";
description = "The Overseerr integration monitors data from your Overseerr instance.";
homepage = "https://github.com/vaparr/ha-overseerr";
maintainers = [ ];
};
};
in
{
services.home-assistant.customComponents = [
ha-overseerr
];
}

View File

@@ -0,0 +1,27 @@
{ pkgs, ... }:
let
ha-petlibro = pkgs.buildHomeAssistantComponent rec {
owner = "jjjonesjr33";
domain = "petlibro";
version = "v1.0.22.3";
src = pkgs.fetchFromGitHub {
owner = owner;
repo = "petlibro";
rev = version;
hash = "sha256-fYzy4OpK9Fs+KQ44H4G6DJlcSg9Zyi56fjsmdxDBviM=";
};
meta = {
changelog = "https://github.com/jjjonesjr33/petlibro/releases/tag/${version}";
description = "PETLIBRO integration for Home Assistant.";
homepage = "https://github.com/jjjonesjr33/petlibro";
maintainers = [ ];
};
};
in
{
services.home-assistant.customComponents = [
ha-petlibro
];
}

View File

@@ -0,0 +1,59 @@
{ pkgs, ... }:
let
wyzeapy = pkgs.python3Packages.buildPythonPackage rec {
pname = "wyzeapy";
version = "0.5.27";
format = "pyproject";
src = pkgs.fetchFromGitHub {
owner = "SecKatie";
repo = "wyzeapy";
rev = version;
sha256 = "sha256-IfhRsVWj/bcKOtpCdmpgrz3L8iY73e+weHlOo5rfKHw=";
};
buildInputs = with pkgs.python3Packages; [ poetry-core ];
nativeBuildInputs = with pkgs.python3Packages; [
aiodns
aiohttp
pycryptodome
];
doCheck = false; # no tests in the PyPI tarball
};
ha-wyzeapi = pkgs.buildHomeAssistantComponent rec {
owner = "SecKatie";
domain = "wyzeapi";
version = "0.1.33";
src = pkgs.fetchFromGitHub {
owner = owner;
repo = "ha-wyzeapi";
rev = version;
hash = "sha256-Hl1Vmi2lhoJW3bdkrtO2mNqfLxURPwqFPjYgdrHRxYk=";
};
propagatedBuildInputs = [
wyzeapy
];
postPatch = ''
substituteInPlace custom_components/wyzeapi/manifest.json \
--replace '"wyzeapy>=0.5.28,<0.6"' '"wyzeapy>=0.5.27,<0.6"'
'';
meta = {
changelog = "https://github.com/SecKatie/ha-wyzeapi/releases/tag/${version}";
description = "This is a custom component to allow control of various Wyze devices in Home Assistant using the unofficial API.";
homepage = "https://github.com/SecKatie/ha-wyzeapi";
maintainers = [ ];
};
};
in
{
services.home-assistant.customComponents = [
ha-wyzeapi
];
}

View File

@@ -0,0 +1,62 @@
{ dream2nix, ... }:
let
hostAddress = "10.0.1.4";
localAddress = "10.0.4.2";
hassPort = 8123;
in
{
containers.homeassistant = {
autoStart = true;
privateNetwork = true;
hostAddress = hostAddress;
localAddress = localAddress;
bindMounts = {
"/var/lib/homeassistant" = {
hostPath = "/var/lib/homeassistant";
isReadOnly = false;
};
USB0 = {
hostPath = "/dev/ttyUSB0";
mountPoint = "/dev/ttyUSB0";
isReadOnly = false;
};
};
config = { lib, ... }:
{
imports = [
./homeassistant.nix
];
networking = {
firewall = {
enable = true;
allowedTCPPorts = [ hassPort ];
};
# Use systemd-resolved inside the container
# Workaround for bug https://github.com/NixOS/nixpkgs/issues/162686
useHostResolvConf = lib.mkForce false;
};
# Create and set permissions for required directories
system.activationScripts.hass-dirs = ''
mkdir -p /var/lib/homeassistant
chown -R homeassistant:homeassistant /var/lib/homeassistat
chmod -R 775 /var/lib/homeassistant
'';
services.resolved.enable = true;
system.stateVersion = "23.11";
};
};
networking.nat = {
forwardPorts = [
{
destination = "${localAddress}:${toString hassPort}";
sourcePort = hassPort;
}
];
};
}

View File

@@ -0,0 +1,394 @@
{ config, lib, pkgs, ... }:
let
mosquittoPort = 1883;
zigbee2mqttPort = 8080;
# In configuration.nix or a separate file
python-steam = pkgs.python3Packages.buildPythonPackage rec {
pname = "steam";
version = "1.4.4";
pyproject = false;
src = pkgs.fetchPypi {
inherit pname version;
sha256 = "sha256-K1vWkRwNSnMS9EG40WK52NR8i+u478bIhnOTsDI/pS4=";
};
buildInputs = with pkgs.python3Packages; [ setuptools ];
doCheck = false; # no tests in the PyPI tarball
};
in
{
imports = [ ./hacs ];
services.home-assistant = {
enable = true;
openFirewall = true;
configDir = "/var/lib/homeassistant";
configWritable = true; # todo
extraComponents = [
"adguard"
"apple_tv"
"analytics"
"bluetooth"
"bluetooth_adapters"
"bluetooth_le_tracker"
"bluetooth_tracker"
"brother"
"caldav"
"calendar"
"cloudflare"
"co2signal"
"color_extractor"
"holiday"
"jellyfin"
"music_assistant"
"nut"
"nextcloud"
"nws"
"ollama"
"onedrive"
"ping"
"samsungtv"
"season"
"simplefin"
"smartthings"
"upnp"
"workday"
"wyoming"
"google_translate"
"met"
"radio_browser"
"shopping_list"
"esphome"
# Recommended for fast zlib compression
# https://www.home-assistant.io/integrations/isal
"isal"
"subaru"
"vesync"
"mqtt" # Enables MQTT integration in HA
"ffmpeg" # Enables camera streams
"zha" # Enables Zigbee integration
"homekit"
"music_assistant"
];
customComponents = with pkgs.home-assistant-custom-components; [
auth-header
localtuya
];
customLovelaceModules = with pkgs.home-assistant-custom-lovelace-modules; [
atomic-calendar-revive
bubble-card
button-card
hourly-weather
mini-graph-card
mini-media-player
multiple-entity-row
mushroom
vacuum-card
weather-chart-card
zigbee2mqtt-networkmap
];
# use postgresql instead of sqlite
extraPackages = ps: with ps; [
# Core functionality
aiohttp
aiodns
paho-mqtt
pillow
pytz
pyyaml
sqlalchemy
# Discovery & networking
zeroconf
netdisco
ifaddr
ssdp
# Device protocols
pyserial # Serial communications
bluepy # Bluetooth LE
# Smart home ecosystems
mutagen # Media file metadata
pysonos # Sonos
pywemo # Belkin WeMo
python-miio # Xiaomi devices
python-kasa # TP-Link
# Sensors & monitoring
meteocalc # Weather calculations
speedtest-cli # Internet speed
# Visualization & UI
matplotlib # Graphing
# Security
bcrypt
cryptography
pyjwt
# Media
ha-ffmpeg # Camera streams
# Specialized integrations
python-matter-server # Matter protocol
# System integrations
psutil # System monitoring
psycopg2
numpy
hassil
pyturbojpeg
paho-mqtt
pychromecast
pyatv
python-otbr-api
brother
pyipp
govee-ble
adguardhome
nextcord
aiogithubapi
jellyfin-apiclient-python
pylitterbot
dateparser
aionut
nextcloudmonitor
ollama
pynecil
aiopyarr
pysabnzbd
getmac
zigpy
bellows # For Zigbee EmberZNet-based adapters
zigpy-xbee # For XBee adapters
zigpy-deconz # For ConBee/RaspBee adapters
pyicloud # iCloud
pyatv # Apple TV
opencv-python
face-recognition
ibeacon-ble
gehomesdk
onedrive-personal-sdk
python-roborock
python-steam
apple-weatherkit
samsungctl
samsungtvws
aiohomekit
icmplib
aioelectricitymaps
wyoming
pysmartthings
wakeonlan
ephem
];
config = {
# Includes dependencies for a basic setup
# https://www.home-assistant.io/integrations/default_config/
default_config = {};
cloud = false;
frontend = {
themes = "!include_dir_merge_named themes";
};
"automation ui" = "!include automations.yaml";
"scene ui" = "!include scenes.yaml";
"script ui" = "!include scripts.yaml";
http = {
use_x_forwarded_for = true;
trusted_proxies = [
"172.30.33.0/24"
"10.0.1.4"
"10.0.4.2"
"10.0.1.18"
"10.0.1.0/24"
];
};
recorder = {
db_url = "postgresql://@/hass";
purge_keep_days = 180;
};
auth_header = {
debug = false;
username_header = "X-authentik-username";
};
# https://www.home-assistant.io/integrations/ota_updater/
zha.zigpy_config.ota.z2m_remote_index = "https://raw.githubusercontent.com/Koenkk/zigbee-OTA/master/index.json";
};
};
# https://www.home-assistant.io/integrations/automation/
# systemd.tmpfiles.rules = [
# "f ${config.services.home-assistant.configDir}/automations.yaml 0755 hass hass"
# ];
# This bypasses the component validation and places it directly in HA's data directory
system.activationScripts.installCustomComponents = ''
chown -R hass:hass ${config.services.home-assistant.configDir}
chmod -R 750 ${config.services.home-assistant.configDir}
'';
services = {
postgresql = {
enable = true;
ensureDatabases = [ "hass" ];
ensureUsers = [{
name = "hass";
ensureDBOwnership = true;
}];
};
# Enable and configure Mosquitto MQTT broker
mosquitto = {
enable = true;
listeners = [
{
acl = [ "pattern readwrite #" ];
omitPasswordAuth = true;
settings.allow_anonymous = true;
}
];
};
zigbee2mqtt = {
enable = true;
settings = {
homeassistant = {
enabled = config.services.home-assistant.enable;
# Optional: Home Assistant discovery topic (default: shown below)
# Note: should be different from [MQTT base topic](../mqtt.md) to prevent errors in HA software
discovery_topic = "homeassistant";
# Optional: Home Assistant status topic (default: shown below)
status_topic = "homeassistant/status";
# Optional: Experimental support for Home Assistant event entities, may break in the future (default: shown below) when enabled:
# - An `event` entity will be discovered for each 'action'.
# - The `event_type` attribute will contain the action itself, additional attributes like `button` will have further information.
experimental_event_entities = false;
# Optional: Home Assistant legacy action sensor (default: `false`), when enabled:
# - Zigbee2MQTT will send an empty 'action' after one has been send
# - A 'sensor_action' will be discovered
legacy_action_sensor = false;
};
permit_join = true;
# Web interface
frontend = {
port = zigbee2mqttPort; # Choose an available port
};
# MQTT configuration
mqtt = {
base_topic = "zigbee2mqtt";
server = "mqtt://localhost:1883";
# If using authentication:
# user = "mqttuser";
# password = "your-password";
};
serial = {
port = "/dev/ttyUSB0";
};
};
};
music-assistant = {
enable = true;
providers = [
# "airplay" # music-assistant: airplay support is missing libraop, a library we will not package because it depends on OpenSSL 1.1.
"apple_music"
"bluesound"
"builtin"
"chromecast"
"deezer"
"dlna"
"fanarttv"
"filesystem_local"
"filesystem_smb"
"fully_kiosk"
"hass"
"hass_players"
"jellyfin"
"musicbrainz"
"opensubsonic"
"player_group"
"plex"
"qobuz"
"radiobrowser"
"siriusxm"
"snapcast"
"sonos"
"sonos_s1"
"soundcloud"
"spotify"
"template_player_provider"
"test"
"theaudiodb"
"tidal"
"tunein"
"ytmusic"
];
};
# Enable AirPlay
pipewire = {
# opens UDP ports 6001-6002
raopOpenFirewall = true;
extraConfig.pipewire = {
"10-airplay" = {
"context.modules" = [
{
name = "libpipewire-module-raop-discover";
# increase the buffer size if you get dropouts/glitches
# args = {
# "raop.latency.ms" = 500;
# };
}
];
};
};
};
};
# Enable required hardware support for the Zigbee adapter
hardware.bluetooth.enable = true; # Some adapters use Bluetooth
# Ensure proper permissions for Zigbee USB devices
# services.udev.extraRules = ''
# # For CC2531, CC2530, CC1352P-2, CC2538 and similar adapters
# SUBSYSTEM=="tty", ATTRS{idVendor}=="0451", ATTRS{idProduct}=="16a8", SYMLINK+="zigbee", MODE="0666"
# SUBSYSTEM=="tty", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", SYMLINK+="zigbee", MODE="0666"
# # For ConBee/RaspBee by Dresden Elektronik
# SUBSYSTEM=="tty", ATTRS{idVendor}=="1cf1", ATTRS{idProduct}=="0030", SYMLINK+="zigbee", MODE="0666"
# # For Electrolama zig-a-zig-ah (zzh!)
# SUBSYSTEM=="tty", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", SYMLINK+="zigbee", MODE="0666"
# '';
environment.systemPackages = with pkgs; [
mosquitto # MQTT command-line tools
usbutils # For lsusb to help identify your adapter
];
networking.firewall.allowedTCPPorts = [
mosquittoPort
zigbee2mqttPort
8095
8097
];
}

View File

View File

View File

@@ -0,0 +1,14 @@
let configDir = ./config;
in
{
imports = [
./config/nwg-dock
./config/nwg-drawer
./config/nwg-panel
];
home.file = {
".config/wallpapers".source = "${configDir}/wallpapers";
".config/wlogout".source = "${configDir}/wlogout";
".config/waybar/scripts".source = "${configDir}/waybar/scripts";
};
}

View File

@@ -0,0 +1,122 @@
{ pkgs, hyprlandSettings, ... }:
let
settings = import ../../settings.nix { inherit pkgs; };
in
{
programs.btop = {
enable = true;
settings = {
color_theme = "nord";
theme_background = true;
truecolor = true;
force_tty = false;
presets = "cpu:1:default,proc:0:default cpu:0:default,mem:0:default,net:0:default cpu:0:block,net:0:tty";
vim_keys = true;
rounded_corners = true;
graph_symbol = "braille";
graph_symbol_cpu = "default";
graph_symbol_mem = "default";
graph_symbol_net = "default";
graph_symbol_proc = "default";
shown_boxes = "cpu mem net proc";
update_ms = 2000;
proc_sorting = "cpu lazy";
proc_reversed = false;
proc_tree = false;
proc_colors = true;
proc_gradient = true;
proc_per_core = false;
proc_mem_bytes = true;
proc_cpu_graphs = true;
proc_info_smaps = false;
proc_left = false;
proc_filter_kernel = false;
cpu_graph_upper = "total";
cpu_graph_lower = "total";
cpu_invert_lower = true;
cpu_single_graph = false;
cpu_bottom = false;
show_uptime = true;
check_temp = true;
cpu_sensor = "Auto";
show_coretemp = true;
cpu_core_map = "";
temp_scale = "celsius";
base_10_sizes = false;
show_cpu_freq = true;
clock_format = "%X";
background_update = true;
custom_cpu_name = "";
disks_filter = "";
mem_graphs = true;
mem_below_net = false;
zfs_arc_cached = true;
show_swap = true;
swap_disk = true;
show_disks = true;
only_physical = true;
use_fstab = true;
zfs_hide_datasets = false;
disk_free_priv = false;
show_io_stat = true;
io_mode = false;
io_graph_combined = false;
io_graph_speeds = "";
net_download = 100;
net_upload = 100;
net_auto = true;
net_sync = true;
net_iface = "";
show_battery = true;
selected_battery = "Auto";
log_level = "WARNING";
};
themes = {
nord = ''
theme[main_bg]="${settings.theme.nord.polarNight.nord0}"
theme[main_fg]="${settings.theme.nord.snowStorm.nord6}"
theme[title]="${settings.theme.nord.snowStorm.nord6}"
theme[hi_fg]="${settings.theme.nord.frost.nord7}"
theme[selected_bg]="${settings.theme.nord.polarNight.nord1}"
theme[selected_fg]="${settings.theme.nord.frost.nord7}"
theme[inactive_fg]="${settings.theme.nord.polarNight.nord2}"
theme[graph_text]="${settings.theme.nord.snowStorm.nord6}"
theme[meter_bg]="${settings.theme.nord.polarNight.nord1}"
theme[proc_misc]="${settings.theme.nord.snowStorm.nord6}"
theme[cpu_box]="${settings.theme.nord.aurora.nord15}"
theme[mem_box]="${settings.theme.nord.aurora.nord14}"
theme[net_box]="${settings.theme.nord.aurora.nord12}"
theme[proc_box]="${settings.theme.nord.aurora.nord11}"
theme[div_line]="${settings.theme.nord.polarNight.nord1}"
theme[temp_start]="${settings.theme.nord.aurora.nord14}"
theme[temp_mid]="${settings.theme.nord.aurora.nord13}"
theme[temp_end]="${settings.theme.nord.aurora.nord11}"
theme[cpu_start]="${settings.theme.nord.aurora.nord15}"
theme[cpu_mid]="${settings.theme.nord.aurora.nord12}"
theme[cpu_end]="${settings.theme.nord.aurora.nord11}"
theme[free_start]="${settings.theme.nord.aurora.nord14}"
theme[free_mid]="${settings.theme.nord.aurora.nord13}"
theme[free_end]="${settings.theme.nord.aurora.nord12}"
theme[cached_start]="${settings.theme.nord.aurora.nord14}"
theme[cached_mid]="${settings.theme.nord.aurora.nord13}"
theme[cached_end]="${settings.theme.nord.aurora.nord12}"
theme[available_start]="${settings.theme.nord.snowStorm.nord6}"
theme[available_mid]="${settings.theme.nord.aurora.nord11}"
theme[available_end]="${settings.theme.nord.aurora.nord11}"
theme[used_start]="${settings.theme.nord.aurora.nord14}"
theme[used_mid]="${settings.theme.nord.aurora.nord13}"
theme[used_end]="${settings.theme.nord.aurora.nord11}"
theme[download_start]="${settings.theme.nord.frost.nord8}"
theme[download_mid]="${settings.theme.nord.frost.nord8}"
theme[download_end]="${settings.theme.nord.aurora.nord12}"
theme[upload_start]="${settings.theme.nord.frost.nord7}"
theme[upload_mid]="${settings.theme.nord.frost.nord7}"
theme[upload_end]="${settings.theme.nord.aurora.nord12}"
theme[process_start]="${settings.theme.nord.aurora.nord15}"
theme[process_mid]="${settings.theme.nord.aurora.nord12}"
theme[process_end]="${settings.theme.nord.aurora.nord11}"
'';
};
};
}

View File

@@ -0,0 +1,314 @@
{ pkgs, hyprlandSettings, ... }:
let
settings = import ../../settings.nix { inherit pkgs; };
drawer = "nwg-drawer -fm nautilus -term kitty -mb 10 -mt 10 -ml 10 -mr 10 -pbuseicontheme -i ${settings.iconTheme}";
in
{
wayland.windowManager.hyprland = {
enable = true;
xwayland.enable = true;
systemd.enable = true;
settings = {
"$mod" = "SUPER";
# Mouse
# mouse_[up|down] - scroll wheel
# middle_mouse - 274
# thumb_up - 276
# thumb_down - 275
# l -> locked, will also work when an input inhibitor (e.g. a lockscreen) is active.
# r -> release, will trigger on release of a key.
# e -> repeat, will repeat when held.
# n -> non-consuming, key/mouse events will be passed to the active window in addition to triggering the dispatcher.
# m -> mouse, see below.
# t -> transparent, cannot be shadowed by other binds.
# i -> ignore mods, will ignore modifiers.
# s -> separate, will arbitrarily combine keys between each mod/key, see [Keysym combos](#keysym-combos) above.
# d -> has description, will allow you to write a description for your bind.
# p -> bypasses the app's requests to inhibit keybinds.
# https://wiki.hyprland.org/Configuring/Binds/
# https://wiki.hyprland.org/Configuring/Binds/#mouse-buttons
bind = [
"$mod, Return, exec, ${settings.defaultApps.terminal.pname}"
"$mod, SPACE, exec, wofi --show drun"
", xf86Search, exec, wofi --show drun"
"$mod, Q, killactive, "
"$mod, M, exec, wlogout --protocol layer-shell"
"$mod, E, exec, ${settings.defaultApps.fileExplorer.pname}"
"$mod, V, togglefloating, "
"$mod, D, exec, ${drawer}"
"$mod, P, pseudo, " # dwindle
"$mod, S, togglesplit, " # dwindle
"$mod SHIFT, Q, exec, hyprlock"
"$mod SHIFT, 4, exec, hyprshot -m region --clipboard-only"
"$mod, F, fullscreen, 1"
"$mod SHIFT, F, fullscreen, 0"
"$mod SHIFT, E, exec, smile"
"$mod, mouse:276, movecurrentworkspacetomonitor, ${settings.displayLeft.input}"
"$mod, mouse:275, movecurrentworkspacetomonitor, ${settings.displayRight.input}"
# alt-tab between workspaces on active monitor
"$mod, Tab, workspace, m+1"
"$mod SHIFT, Tab, workspace, m-1"
"$mod, h, movefocus, l"
"$mod, l, movefocus, r"
"$mod, k, movefocus, u"
"$mod, j, movefocus, d"
"$mod, 1, workspace, 1"
"$mod, 2, workspace, 2"
"$mod, 3, workspace, 3"
"$mod, 4, workspace, 4"
"$mod, 5, workspace, 5"
"$mod, 6, workspace, 6"
"$mod, 7, workspace, 7"
"$mod, 8, workspace, 8"
"$mod, 9, workspace, 9"
"$mod, 0, workspace, 10"
"$mod ALT, 1, movetoworkspace, 1"
"$mod ALT, 2, movetoworkspace, 2"
"$mod ALT, 3, movetoworkspace, 3"
"$mod ALT, 4, movetoworkspace, 4"
"$mod ALT, 5, movetoworkspace, 5"
"$mod ALT, 6, movetoworkspace, 6"
"$mod ALT, 7, movetoworkspace, 7"
"$mod ALT, 8, movetoworkspace, 8"
"$mod ALT, 9, movetoworkspace, 9"
"$mod ALT, 0, movetoworkspace, discord"
"$mod CTRL, l, resizeactive, 10 0"
"$mod CTRL, h, resizeactive, -10 0"
"$mod CTRL, k, resizeactive, 0 -10"
"$mod CTRL, j, resizeactive, 0 10"
"$mod SHIFT, l, movewindow, r"
"$mod SHIFT, h, movewindow, l"
"$mod SHIFT, k, movewindow, u"
"$mod SHIFT, j, movewindow, d"
"$mod, b, exec, ${settings.defaultApps.browser.pname}"
];
bindm = [
# Move/resize windows with mod + LMB/RMB and dragging
"$mod, mouse:272, movewindow"
"$mod, mouse:273, resizewindow"
# middle mouse will grab a window, mod + middle mouse will close it
"$mod SHIFT, mouse:274, movewindow"
];
bindel = [
", XF86AudioRaiseVolume, exec, wpctl set-volume -l 1.5 @DEFAULT_AUDIO_SINK@ 5%+"
", XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-"
];
bindl = [
", XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle"
", XF86AudioPlay, exec, playerctl play-pause"
", XF86AudioPrev, exec, playerctl previous"
", XF86AudioNext, exec, playerctl next"
", XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle"
", XF86MonBrightnessUp, exec, brightnessctl set +5%"
", XF86MonBrightnessDown, exec, brightnessctl set 5%-"
"$mod, XF86MonBrightnessUp, exec, brightnessctl -d kbd_backlight set +10%"
"$mod, XF86MonBrightnessDown, exec, brightnessctl -d kbd_backlight set 10%-"
];
monitor = hyprlandSettings.monitor or [ ];
monitorv2 = hyprlandSettings.monitorv2 or { };
render = {
cm_fs_passthrough = 1;
};
misc = {
vrr = 1;
};
general = {
gaps_in = 5;
gaps_out = 10;
border_size = 1;
"col.active_border" = "rgb(8aadf4) rgb(24273A) rgb(24273A) rgb(8aadf4) 45deg";
"col.inactive_border" = "rgb(24273A) rgb(24273A) rgb(24273A) rgb(24273A) 45deg";
layout = "dwindle";
allow_tearing = true;
};
decoration = {
rounding = 10;
blur = {
enabled = true;
size = 2;
passes = 2;
new_optimizations = true;
xray = false;
};
# drop_shadow = "yes";
# shadow_range = 4;
# shadow_render_power = "3";
# "col.shadow" = "rgba(1a1a1aee)";
};
animations = {
enabled = "yes";
bezier = [
"overshot, 0.05, 0.9, 0.1, 1.05"
"smoothOut, 0.36, 0, 0.66, -0.56"
"smoothIn, 0.25, 1, 0.5, 1"
];
animation = [
"windows, 1, 5, overshot, slide"
"windowsOut, 1, 4, smoothOut, slide"
"windowsMove, 1, 4, default"
"border, 1, 10, default"
"fade, 1, 10, smoothIn"
"fadeDim, 1, 10, smoothIn"
"workspaces, 1, 6, default"
];
};
dwindle = {
pseudotile = "yes";
preserve_split = "yes";
};
gestures = {
workspace_swipe = "off";
};
misc = {
force_default_wallpaper = 0;
};
workspace = hyprlandSettings.workspace;
windowrule = [
"float, title:(file_progress)"
"float, title:(.*[Cc]onfirm.*)"
"float, title:(.*[Dd]ialog.*)"
"float, title:(.*[Dd]ownload.*)"
"float, title:(.*[Nn]otification.*)"
"float, title:(.*[Ee]rror.*)"
"float, title:(.*[Ss]plash.*)"
"float, title:(.*[Cc]onfirmreset.*)"
"float, title:(.*[Ss]ign [Ii]n - .*)"
"float, title:(.*[Oo]pen [Ff]ile.*)"
"float, title:(.*branchdialog.*)"
"float, class:(.*pavucontrol.*)"
"move onscreen cursor 0% 0%, class:(.*pavucontrol.*)"
"float, class:(.*[Oo]verskride.*)"
"float, class:(.*FileRoller.*)"
"float, class:(.*wlogout.*)"
"idleinhibit stayfocused, title:(.*mpv.*)"
"float, class:(.*nm-connection-editor.*)"
"move onscreen cursor 0% 0%, class:(.*nm-connection-editor.*)"
"float, title:(Media viewer)"
"float, class:(it.mijorus.smile),title:(Smile)"
"float, class:(.blueman-manager-wrapped)$,title:(Bluetooth Devices)"
# Picture in picture windows
"float, title:(.*Picture-in-Picture.*)"
"pin, title::(.*Picture-in-Picture.*)"
# discord/vesktop
"workspace: name:discord, class:(.*vesktop)"
"float, class:(.*vesktop),title:(.*Discord Popout.*)"
"pin, class:(.*vesktop),title:(.*Discord Popout.*)"
# Music
"workspace: name:discord, class:(Apple Music.*)"
# Steam
"float, class:(.*[Ss]team), title:(.*[Ss]team.*)$"
"workspace name:steam silent, class:(.*[Ss]team), title:(.*[Ss]team.*)$"
"tile, class:(.*[Ss]team), title:(.*[Ss]team.*)$"
"float, class:(.*steam),title:(.*Friends List.*)"
# Code
"pin, class:(.*codium.*),title:(Save As)"
"float, class:(.*codium.*),title:(Save As)"
"float, class:(xdg-desktop-portal-gtk),title:(Open Workspace from File)"
# Game Tearing??? https://wiki.hyprland.org/Configuring/Tearing/
"immediate, class:(.*gamescope)"
# vmware
# this tag will set the below options to the vdi window
# this will have it auto open as a 2160x7680 window
# and makes multi-monitor work
"tag +horizonrdp, class:(.*[Vv][Mm]ware-view),title:(USPS Next VDI)"
"noanim, tag:horizonrdp"
"noblur, tag:horizonrdp"
"norounding, tag:horizonrdp"
"noshadow, tag:horizonrdp"
"immediate, tag:horizonrdp"
"allowsinput, tag:horizonrdp"
"noborder, tag:horizonrdp"
"nodim, tag:horizonrdp"
"nomaxsize, tag:horizonrdp"
"renderunfocused, tag:horizonrdp"
"idleinhibit, tag:horizonrdp"
"float, tag:horizonrdp"
# "size 2160 7680, tag:horizonrdp"
# "move onscreen 0 0, tag:horizonrdp"
# float the vmware window cause its annoying to use in fullscreen
"float, class:(.*[Vv][Mm]ware-view),title:([Vv][Mm]ware [Hh]orizon [Cc]lient)"
"tag +waydroid, class:([Ww]aydroid.*)"
"float, tag:waydroid"
"pin, tag:waydroid"
] ++ hyprlandSettings.windowRule;
input = {
kb_layout = "us";
kb_variant = "";
kb_model = "";
kb_options = "";
kb_rules = "";
numlock_by_default = true;
follow_mouse = 1;
touchpad = {
clickfinger_behavior = 1;
natural_scroll = "yes";
};
sensitivity = 0; # -1.0 - 1.0, 0 means no modification.
};
experimental = {
xx_color_management_v4 = true;
};
debug = {
full_cm_proto = true;
disable_logs = true;
disable_scale_checks = true;
};
};
extraConfig = ''
exec-once = dbus-update-activation-environment --systemd --all
exec-once = systemctl --user import-environment WAYLAND_DISPLAY XDG_CURRENT_DESKTOP
exec-once = /usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1
exec-once = xhost +SI:localuser:root
exec-once = nwg-look -a
exec-once = nwg-dock-hyprland -d
'' + hyprlandSettings.extraConfig or '''';
};
}

View File

@@ -0,0 +1,100 @@
{ pkgs, hyprlandSettings, ... }:
let
settings = import ../../settings.nix { inherit pkgs; };
in
{
programs.kitty = {
enable = true;
shellIntegration.enableZshIntegration = true;
font = {
name = settings.fontName;
package = settings.fontPackage;
size = settings.fontSize;
};
settings = {
bold_font = "auto";
italic_font = "auto";
bold_italic_font = "auto";
mouse_hide_wait = "2.0";
cursor_shape = "block";
url_style = "dotted";
confirm_os_window_close = "0";
background_opacity = "0.85";
# The basic colors
foreground = settings.theme.nord.snowStorm.nord6;
background = settings.theme.nord.polarNight.nord0;
selection_foreground = settings.theme.nord.polarNight.nord0;
selection_background = settings.theme.nord.aurora.nord15;
# Cursor colors
cursor = settings.theme.nord.aurora.nord15;
cursor_text_color = settings.theme.nord.polarNight.nord0;
# URL underline color when hovering with mouse
url_color = settings.theme.nord.aurora.nord15;
# Kitty window border colors
active_border_color = settings.theme.nord.frost.nord10;
inactive_border_color = settings.theme.nord.polarNight.nord1;
bell_border_color = settings.theme.nord.aurora.nord13;
# OS Window titlebar colors
wayland_titlebar_color = settings.theme.nord.polarNight.nord0;
macos_titlebar_color = settings.theme.nord.polarNight.nord0;
# Tab bar colors
active_tab_foreground = settings.theme.nord.polarNight.nord3;
active_tab_background = settings.theme.nord.aurora.nord15;
inactive_tab_foreground = settings.theme.nord.snowStorm.nord6;
inactive_tab_background = settings.theme.nord.polarNight.nord1;
tab_bar_background = settings.theme.nord.polarNight.nord3;
# Colors for marks (marked text in the terminal)
mark1_foreground = settings.theme.nord.polarNight.nord0;
mark1_background = settings.theme.nord.frost.nord10;
mark2_foreground = settings.theme.nord.polarNight.nord0;
mark2_background = settings.theme.nord.aurora.nord15;
mark3_foreground = settings.theme.nord.polarNight.nord0;
mark3_background = settings.theme.nord.frost.nord8;
# The 16 terminal colors
# black
color0 = settings.theme.nord.polarNight.nord0;
# Autosuggestion
color8 = settings.theme.nord.frost.nord10;
# red
color1 = settings.theme.nord.aurora.nord11;
color9 = settings.theme.nord.aurora.nord11;
# green
color2 = settings.theme.nord.aurora.nord14;
color10 = settings.theme.nord.aurora.nord14;
# yellow
color3 = settings.theme.nord.aurora.nord13;
color11 = settings.theme.nord.aurora.nord13;
# blue
color4 = settings.theme.nord.frost.nord10;
color12 = settings.theme.nord.frost.nord10;
# magenta
color5 = settings.theme.nord.aurora.nord15;
color13 = settings.theme.nord.aurora.nord15;
# cyan
color6 = settings.theme.nord.frost.nord8;
color14 = settings.theme.nord.frost.nord8;
# white
color7 = settings.theme.nord.snowStorm.nord5;
color15 = settings.theme.nord.snowStorm.nord4;
};
};
}

View File

@@ -0,0 +1,27 @@
{ pkgs, hyprlandSettings, ... }:
let
settings = import ../../settings.nix { inherit pkgs; };
in
{
services.mako = {
enable = true;
settings = {
font = settings.fontName;
icons = true;
ignore-timeout = true;
sort = "-time";
width = 500;
height = 110;
layer = "overlay";
border-radius = 15;
border-size = 1;
max-icon-size = 64;
default-timeout = 5000;
background-color = settings.theme.nord.polarNight.nord0;
text-color = settings.theme.nord.snowStorm.nord6;
border-color = settings.theme.nord.frost.nord10;
progress-color = "over ${settings.theme.nord.frost.nord8}";
};
};
}

View File

@@ -0,0 +1,52 @@
{ pkgs, hyprlandSettings, ... }:
let
settings = import ../../settings.nix { inherit pkgs; };
in
{
home.file = {
".config/nwg-dock-hyprland/drawer.css".text = ''
window {
background: ${settings.theme.nord.polarNight.nord0};
border-radius: 10px;
border-style: none;
border-width: 1px;
border-color: ${settings.theme.nord.aurora.nord15}b0
}
#box {
/* Define attributes of the box surrounding icons here */
padding: 10px
}
active {
/* This is to underline the button representing the currently active window */
border-bottom: solid 1px;
border-color: ${settings.theme.nord.aurora.nord14}1a
}
button, image {
background: none;
border-style: none;
box-shadow: none;
color: ${settings.theme.nord.frost.nord10}
}
button {
padding: 4px;
margin-left: 4px;
margin-right: 4px;
color: #eee;
font-size: 12px
}
button:hover {
background-color: ${settings.theme.nord.polarNight.nord0}1a;
border-radius: 2px;
}
button:focus {
box-shadow: none
}
'';
};
}

View File

@@ -0,0 +1,44 @@
{ pkgs, hyprlandSettings, ... }:
let
settings = import ../../settings.nix { inherit pkgs; };
in
{
home.file = {
".config/nwg-drawer/drawer.css".text = ''
window {
background-color: ${settings.theme.nord.polarNight.nord0}bf;
color: ${settings.theme.nord.snowStorm.nord5}00
}
/* search entry */
entry {
background-color: ${settings.theme.nord.polarNight.nord1}0f
}
button, image {
background: none;
border: none
}
button:hover {
background-color: ${settings.theme.nord.frost.nord10}1a
}
/* in case you wanted to give category buttons a different look */
#category-button {
margin: 0 10px 0 10px
}
#pinned-box {
padding-bottom: 5px;
border-bottom: 1px dotted ${settings.theme.nord.polarNight.nord3}
}
#files-box {
padding: 5px;
border: 1px dotted ${settings.theme.nord.polarNight.nord3};
border-radius: 15px
}
'';
};
}

View File

@@ -0,0 +1,21 @@
{ pkgs, hyprlandSettings, ... }:
let
settings = import ../../settings.nix { inherit pkgs; };
in
{
home.file = {
".config/nwg-panel/excluded-dirs".text = ''
'';
".config/nwg-panel/preferred-apps.json".text = ''
{
"\\.pdf$": "${settings.defaultApps.browser.pname}",
"\\.svg$": "inkscape",
"\\.(jpg|png|tiff|gif)$": "${settings.defaultApps.imageViewer.pname}",
"\\.(mp3|ogg|flac|wav|wma)$": "audacious",
"\\.(avi|mp4|mkv|mov|wav)$": "${settings.defaultApps.video.pname}",
"\\.(doc|docx|xls|xlsx)$": "${settings.defaultApps.office.pname}"
}
'';
};
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 KiB

View File

@@ -0,0 +1,505 @@
{ pkgs, hyprlandSettings, ... }:
let
settings = import ../../settings.nix { inherit pkgs; };
defaultOpacity = settings.theme.waybar.defaultOpacity;
defaultBorderRadius = settings.theme.waybar.defaultBorderRadius;
defaultCenterOptions = settings.theme.waybar.defaultCenterOptions;
borderLeft = settings.theme.waybar.borderLeft;
borderRight = settings.theme.waybar.borderRight;
in
{
imports = [
./scripts/hass.nix
./scripts/weather.nix
];
# https://github.com/Alexays/Waybar/wiki/Module:-Hyprland
# https://www.nerdfonts.com/cheat-sheet
programs.waybar = {
enable = true;
systemd.enable = true;
settings = {
mainBar = {
layer = hyprlandSettings.waybar.layer;
position = "top";
mod = "dock";
exclusive = true;
passthrough = false;
gtk-layer-shell = true;
height = 0;
# Module Layout
modules-left = [ "hyprland/workspaces" ];
modules-center = [ "hyprland/window" ];
modules-right = hyprlandSettings.waybar.modules-right;
# Module Definitions
# Left
"hyprland/workspaces" = {
disable-scroll = true;
all-outputs = true;
on-click = "activate";
persistent_workspaces = {
"*" = 1;
};
};
# Center
"hyprland/window" = {
separate-outputs = true;
format = { };
};
# Left
tray = {
icon-size = 16;
spacing = 10;
};
temperature = {
hwmon-path = "/sys/class/hwmon/hwmon4/temp1_input";
critical-threshold = 110;
format-critical = "{temperatureC}°C ";
format = "{temperatureC}°C {icon}";
format-icons = [
"" # fa-temperature-empty
"" # fa-temperature-quarter
"" # fa-temperature-half
"" # fa-temperature-three-quarters
"" # fa-temperature-full
];
tooltip-format = "CPU: {temperatureC}°C";
};
"temperature#gpu" = {
hwmon-path = "/sys/class/hwmon/hwmon0/temp1_input";
critical-threshold = 110;
format-critical = "{temperatureC}°C ";
format = "{temperatureC}°C {icon}";
format-icons = [
"" # fa-temperature-empty
"" # fa-temperature-quarter
"" # fa-temperature-half
"" # fa-temperature-three-quarters
"" # fa-temperature-full
];
on-click = "lact";
tooltip-format = "GPU: {temperatureC}°C";
};
"keyboard-state#capslock" = {
capslock = true;
format = "{icon}";
tooltip-format = "Caps Lock {state}";
format-icons = {
locked = "󰬶";
unlocked = "󰬵";
};
};
"keyboard-state#numlock" = {
numlock = true;
format = "{icon}";
tooltip-format = "Num Lock {state}";
format-icons = {
locked = "󰎠";
unlocked = "󱧓";
};
};
"wireplumber#sink" = {
format = "{icon} {volume}%";
tooltip = false;
format-muted = "{icon} Muted";
on-click = "wpctl set-mute @DEFAULT_SINK@ toggle";
on-click-right = "pavucontrol -t 1";
on-scroll-up = "wpctl set-volume @DEFAULT_SINK@ 5%+";
on-scroll-down = "wpctl set-volume @DEFAULT_SINK@ 5%-";
scroll-step = 5;
format-icons = {
headphone = "󰋋";
headphone-muted = "󰟎";
hands-free = "󰋋";
headset = "󰋋";
phone = "";
portable = "󰋋";
car = "";
default = [
""
""
""
""
];
};
};
"wireplumber#source" = {
node-type = "Audio/Source";
format = "";
format-muted = "";
tooltip = false;
# tooltip-format = "{source_desc} | {source_volume}%";
on-click = "wpctl set-mute @DEFAULT_SOURCE@ toggle";
on-click-right = "pavucontrol -t 2";
on-scroll-up = "wpctl set-volume @DEFAULT_SOURCE@ 5%+";
on-scroll-down = "wpctl set-volume @DEFAULT_SOURCE@ 5%-";
scroll-step = 5;
};
"bluetooth" = {
on-click = "overskride";
tooltip = true;
format = "{icon}";
tooltip-format = "{status}";
tooltip-format-disabled = "{status}";
tooltip-format-off = "{status}";
tooltip-format-on = "{status}";
tooltip-format-connected = "{status}";
tooltip-format-enumerate-connected = { };
format-icons = {
disabled = "󰂲";
off = "󰂲";
on = "󰂯";
connected = "󰂱";
};
};
network = {
interface = hyprlandSettings.networkInterface;
on-click = "nm-connection-editor";
format = "{icon}";
tooltip-format = "{ifname} via {gwaddr} 󰊗";
tooltip-format-wifi = ''
{essid} ({signalStrength}%) {icon}
{bandwidthDownBits} {bandwidthUpBits}
'';
tooltip-format-ethernet = "{ifname} ";
tooltip-format-disconnected = "Disconnected";
max-length = 50;
format-icons = {
wifi = [
"󰤯"
"󰤟"
"󰤢"
"󰤥"
"󰤨"
];
ethernet = "󰈀";
linked = "󰤫";
disconnected = "󰤫";
};
};
idle_inhibitor = {
format = "{icon}";
format-icons = {
activated = "󰐂";
deactivated = "󱩜";
};
};
clock = {
format = "{:%I:%M %p}";
tooltip-format = "<tt><small>{calendar}</small></tt>";
calendar = {
mode = "month";
format = {
months = "<span color='${settings.theme.nord.frost.nord9}'><b>{}</b></span>";
days = "<span color='${settings.theme.nord.frost.nord10}'><b>{}</b></span>";
weekdays = "<span color='${settings.theme.nord.frost.nord8}'><b>{}</b></span>";
today = "<span color='${settings.theme.nord.aurora.nord14}'><b><u>{}</u></b></span>";
};
};
};
battery = {
# bat = "macsmc-battery";
interval = 60;
# statuses: 'Charging', 'Discharging'
states = {
warning = 30;
critical = 15;
};
format = "{capacity}% {icon}";
format-icons = {
default = [
"󰂃" # critical
"󰁺" # 10%
"󰁻" # 20%
"󰁼" # 30%
"󰁽" # 40%
"󰁾" # 50%
"󰁿" # 60%
"󰂀" # 70%
"󰂁" # 80%
"󰂂" # 90%
"󰁹" # 100%
];
charging = [
"󰢟" # critical
"󰢜" # 10%
"󰂆" # 20%
"󰂇" # 30%
"󰂈" # 40%
"󰢝" # 50%
"󰂉" # 60%
"󰢞" # 70%
"󰂊" # 80%
"󰂋" # 90%
"󰂅" # 100%
];
};
max-length = 25;
};
"custom/weather" = {
tooltip = true;
format = { };
interval = 30;
exec = "waybar-weather";
return-type = "json";
markup = "pango";
};
} // hyprlandSettings.waybar.extraModules or { };
};
# * { font-size: 13px; }
# window.eDP-1 * { font-size: 10px; }
style = ''
.blink_me {
animation: blinker 1s linear infinite;
}
@keyframes blinker {
50% {
color: ${settings.theme.nord.aurora.nord11};
}
}
* {
font-family:
Jetbrains Mono Nerd Font,
monospace;
font-size: 14px;
min-height: 0;
}
#waybar {
background: transparent;
color: ${settings.theme.nord.snowStorm.nord6};
margin: 5px 5px;
}
#workspaces {
background-color: ${settings.theme.nord.polarNight.nord0};
${defaultBorderRadius}
${defaultOpacity}
${defaultCenterOptions}
margin-left: 0.6rem;
}
#workspaces button {
color: ${settings.theme.nord.frost.nord10};
${defaultBorderRadius}
padding: 0.4rem;
}
#workspaces button.active {
color: ${settings.theme.nord.frost.nord8};
${defaultBorderRadius}
}
#workspaces button:hover {
color: ${settings.theme.nord.frost.nord7};
${defaultBorderRadius}
}
#workspaces button.focused {
color: ${settings.theme.nord.snowStorm.nord6};
background: ${settings.theme.nord.aurora.nord13};
${defaultBorderRadius}
}
#workspaces button.urgent {
color: ${settings.theme.nord.polarNight.nord0};
background: ${settings.theme.nord.snowStorm.nord6};
${defaultBorderRadius}
}
#tooltip {
background: ${settings.theme.nord.polarNight.nord0};
border-color: ${settings.theme.nord.polarNight.nord0};
${defaultBorderRadius}
border-width: 1rem;
border-style: solid;
}
#window {
color: ${settings.theme.nord.aurora.nord15};
background-color: ${settings.theme.nord.polarNight.nord0};
${defaultOpacity}
${defaultBorderRadius}
${defaultCenterOptions}
margin-left: ${hyprlandSettings.waybar.moduleStyle.window.margin-left or "4rem"};
margin-right: ${hyprlandSettings.waybar.moduleStyle.window.margin-right or "4rem"};
}
/* make window module transparent when no windows present */
#window.empty {
background-color: transparent;
}
#custom-weather {
color: ${settings.theme.nord.frost.nord10};
background-color: ${settings.theme.nord.polarNight.nord0};
${defaultOpacity}
${borderRight}
}
#battery {
color: ${settings.theme.nord.aurora.nord15};
background-color: ${settings.theme.nord.polarNight.nord0};
${defaultOpacity}
${defaultCenterOptions}
border-radius: 0;
min-width: 3rem;
}
#clock {
color: ${settings.theme.nord.frost.nord9};
background-color: ${settings.theme.nord.polarNight.nord0};
${defaultOpacity}
${borderLeft}
}
/* ------------- */
#idle_inhibitor {
color: ${settings.theme.nord.frost.nord10};
background-color: ${settings.theme.nord.polarNight.nord0};
${defaultOpacity}
${borderRight}
padding-right: 1rem;
}
#idle_inhibitor:hover {
background: ${settings.theme.nord.polarNight.nord3};
}
#network {
color: ${settings.theme.nord.aurora.nord15};
background-color: ${settings.theme.nord.polarNight.nord0};
${defaultOpacity}
${defaultCenterOptions}
border-radius: 0;
padding-right: 15px;
}
#network:hover {
background: ${settings.theme.nord.polarNight.nord3};
}
#bluetooth {
color: ${settings.theme.nord.frost.nord9};
background-color: ${settings.theme.nord.polarNight.nord0};
${defaultOpacity}
${defaultCenterOptions}
border-radius: 0;
}
#bluetooth:hover {
background: ${settings.theme.nord.polarNight.nord3};
}
#wireplumber.source {
color: ${settings.theme.nord.frost.nord8};
background-color: ${settings.theme.nord.polarNight.nord0};
${defaultOpacity}
${defaultCenterOptions}
border-radius: 0;
}
#wireplumber.source.muted {
animation-name: blinker;
animation-duration: 2s;
animation-timing-function: linear;
animation-iteration-count: infinite;
padding-right: 1rem;
}
#wireplumber.source:hover {
background: ${settings.theme.nord.polarNight.nord3};
}
#wireplumber.sink {
color: ${settings.theme.nord.frost.nord7};
background-color: ${settings.theme.nord.polarNight.nord0};
${defaultOpacity}
${defaultCenterOptions}
border-radius: 0;
}
#wireplumber.sink.muted {
animation-name: blinker;
animation-duration: 5s;
animation-timing-function: linear;
animation-iteration-count: infinite;
}
#wireplumber.sink:hover {
background: ${settings.theme.nord.polarNight.nord3};
}
#keyboard-state.numlock {
color: ${settings.theme.nord.frost.nord8};
background-color: ${settings.theme.nord.polarNight.nord0};
${defaultOpacity}
${defaultCenterOptions}
border-radius: 0;
}
#keyboard-state.capslock {
color: ${settings.theme.nord.frost.nord9};
background-color: ${settings.theme.nord.polarNight.nord0};
${defaultOpacity}
${defaultCenterOptions}
border-radius: 0;
}
#temperature.gpu {
color: ${settings.theme.nord.frost.nord10};
background-color: ${settings.theme.nord.polarNight.nord0};
${defaultOpacity}
${defaultCenterOptions}
border-radius: 0;
}
#temperature.gpu:hover {
background: ${settings.theme.nord.polarNight.nord3};
}
#temperature {
color: ${settings.theme.nord.frost.nord9};
background-color: ${settings.theme.nord.polarNight.nord0};
${defaultOpacity}
${hyprlandSettings.waybar.moduleStyle.temperature.location or defaultCenterOptions}
border-radius: ${hyprlandSettings.waybar.moduleStyle.temperature.border-radius or "0"}
}
/* ------------- */
#tray {
background-color: ${settings.theme.nord.polarNight.nord0};
${defaultOpacity}
${defaultCenterOptions}
${defaultBorderRadius}
margin-right: 0.6rem;
}
/* ------------- */
'' + hyprlandSettings.waybar.extraModulesStyle or '''';
};
}

View File

@@ -0,0 +1,106 @@
{ pkgs, ... }:
let
homeassistant-api = pkgs.python3.pkgs.buildPythonPackage rec {
pname = "homeassistant_api";
version = "5.0.0";
format = "pyproject";
src = pkgs.fetchPypi {
inherit pname version;
sha256 = "sha256-UNKTtgInrVJtjHb1WVlUbcbhjBOtTX00eHmm54ww0rY=";
};
# do not run tests
doCheck = false;
nativeBuildInputs = with pkgs.python3.pkgs; [ poetry-core requests-cache ];
dependencies = with pkgs.python3.pkgs; [
requests-cache
pydantic
websockets
];
propagatedBuildInputs = with pkgs.python3.pkgs; [
aiohttp
aiohttp-client-cache
pydantic
requests
requests-cache
simplejson
websockets
];
pythonRelaxDeps = [
"requests-cache"
"pydantic"
"websockets"
];
pythonImportsCheck = [
"homeassistant_api"
];
};
pythonEnv = pkgs.python3.withPackages (ps: [
homeassistant-api
]);
waybar-hass = pkgs.writeScriptBin "waybar-hass" ''
#!${pythonEnv}/bin/python
"""run with the special python"""
import argparse
import time
import json
from homeassistant_api import WebsocketClient
HASS_URL = 'ws://homeassistant.local:8123/api/websocket'
parser = argparse.ArgumentParser(prog='hass python wrapper')
parser.add_argument('--toggle_light')
parser.add_argument('--get_light')
args = parser.parse_args()
def load_key():
"""Read the api key"""
token_path = "/run/secrets/desktop/hass_token"
with open(token_path, "r") as key_file:
key = key_file.readline()
return key
def get_light_state(client, light):
"""Get light status"""
light_entity = client.get_entity(entity_id=light)
state = light_entity.get_state()
if state.state == 'on':
return "󰛨"
return "󰹏"
def toggle_light(client, light):
"""Toggle light status"""
lights = client.get_domain("light")
lights.toggle(entity_id=light)
time.sleep(0.5)
light_entity = client.get_entity(entity_id=light)
state = light_entity.get_state()
if state.state == 'on':
return "󰛨"
return "󰹏"
def main():
"""Main"""
token = load_key()
status = "err"
with WebsocketClient(HASS_URL, token) as client:
# toggle a light
if args.toggle_light is not None:
status = toggle_light(client=client, light=args.toggle_light)
# get the current light status
if args.get_light is not None:
status = get_light_state(client=client, light=args.get_light)
print(json.dumps({ "text": status }))
main()
'';
in
{
home.packages = [ waybar-hass ];
}

View File

@@ -0,0 +1,433 @@
{ pkgs, ... }:
let
waybar-weather = pkgs.writeScriptBin "waybar-weather" ''
#!/usr/bin/env nix-shell
#! nix-shell -i python3 --pure
#! nix-shell -p python3 python3Packages.requests
"""get waybar weather"""
import os
import json
import shutil
from datetime import datetime, timedelta
import requests
WWO_CODE = {
"113": "Sunny",
"116": "PartlyCloudy",
"119": "Cloudy",
"122": "VeryCloudy",
"143": "Fog",
"176": "LightShowers",
"179": "LightSleetShowers",
"182": "LightSleet",
"185": "LightSleet",
"200": "ThunderyShowers",
"227": "LightSnow",
"230": "HeavySnow",
"248": "Fog",
"260": "Fog",
"263": "LightShowers",
"266": "LightRain",
"281": "LightSleet",
"284": "LightSleet",
"293": "LightRain",
"296": "LightRain",
"299": "HeavyShowers",
"302": "HeavyRain",
"305": "HeavyShowers",
"308": "HeavyRain",
"311": "LightSleet",
"314": "LightSleet",
"317": "LightSleet",
"320": "LightSnow",
"323": "LightSnowShowers",
"326": "LightSnowShowers",
"329": "HeavySnow",
"332": "HeavySnow",
"335": "HeavySnowShowers",
"338": "HeavySnow",
"350": "LightSleet",
"353": "LightShowers",
"356": "HeavyShowers",
"359": "HeavyRain",
"362": "LightSleetShowers",
"365": "LightSleetShowers",
"368": "LightSnowShowers",
"371": "HeavySnowShowers",
"374": "LightSleetShowers",
"377": "LightSleet",
"386": "ThunderyShowers",
"389": "ThunderyHeavyRain",
"392": "ThunderySnowShowers",
"395": "HeavySnowShowers",
}
WEATHER_SYMBOL = {
"Unknown": "",
"Cloudy": "",
"Fog": "",
"HeavyRain": "",
"HeavyShowers": "",
"HeavySnow": "",
"HeavySnowShowers": "",
"LightRain": "",
"LightShowers": "",
"LightSleet": "",
"LightSleetShowers": "",
"LightSnow": "",
"LightSnowShowers": "",
"PartlyCloudy": "󰖕",
"Sunny": "",
"ThunderyHeavyRain": "",
"ThunderyShowers": "",
"ThunderySnowShowers": "",
"VeryCloudy": "",
}
WEATHER_CODES = {key: WEATHER_SYMBOL[value] for key, value in WWO_CODE.items()}
WIND_DIRECTION = {
"S": "",
"SW": "",
"W": "",
"NW": "",
"N": "",
"NE": "",
"E": "",
"SE": "",
}
MOON_PHASES = (
"󰽤", "󰽧", "󰽡", "󰽨", "󰽢", "󰽦", "󰽣", "󰽥"
)
WEATHER_SYMBOL_WI_DAY = {
"Unknown": "",
"Cloudy": "",
"Fog": "",
"HeavyRain": "",
"HeavyShowers": "",
"HeavySnow": "",
"HeavySnowShowers": "",
"LightRain": "",
"LightShowers": "",
"LightSleet": "",
"LightSleetShowers": "",
"LightSnow": "",
"LightSnowShowers": "",
"PartlyCloudy": "󰖕",
"Sunny": "",
"ThunderyHeavyRain": "",
"ThunderyShowers": "",
"ThunderySnowShowers": "",
"VeryCloudy": "",
}
WEATHER_CODES_WI_DAY = {key: WEATHER_SYMBOL_WI_DAY[value] for key, value in WWO_CODE.items()}
WEATHER_SYMBOL_WI_NIGHT = {
"Unknown": "",
"Cloudy": "",
"Fog": "",
"HeavyRain": "",
"HeavyShowers": "",
"HeavySnow": "",
"HeavySnowShowers": "",
"LightRain": "",
"LightShowers": "",
"LightSleet": "",
"LightSleetShowers": "",
"LightSnow": "",
"LightSnowShowers": "",
"PartlyCloudy": "󰼱",
"Sunny": "󰖔",
"ThunderyHeavyRain": "",
"ThunderyShowers": "",
"ThunderySnowShowers": "",
"VeryCloudy": "",
}
WEATHER_CODES_WI_NIGHT = {key: WEATHER_SYMBOL_WI_NIGHT[value] for key, value in WWO_CODE.items()}
WEATHER_SYMBOL_WEGO = {
"Unknown": [
" .-. ",
" __) ",
" ( ",
" `- ",
" "],
"Sunny": [
'<span foreground=\"#FFFF00\"> \\ / </span>',
'<span foreground=\"#FFFF00\"> .-. </span>',
'<span foreground=\"#FFFF00\"> ( ) </span>',
'<span foreground=\"#FFFF00\"> `- </span>',
'<span foreground=\"#FFFF00\"> / \\ </span>'],
"PartlyCloudy": [
'<span foreground=\"#FFFF00\"> \\ / </span>',
'<span foreground=\"#FFFF00\"> _ /\'\'</span>"<span foreground=\"#BBBBBB\">.-. </span>',
'<span foreground=\"#FFFF00\"> \\_</span>"<span foreground=\"#BBBBBB\">( ). </span>',
'<span foreground=\"#FFFF00\"> /</span>"<span foreground=\"#BBBBBB\">(___(__) </span>',
' '
],
"Cloudy": [
' ',
'<span foreground=\"#BBBBBB\"> .--. </span>',
'<span foreground=\"#BBBBBB\"> .-( ). </span>',
'<span foreground=\"#BBBBBB\"> (___.__)__) </span>',
' '],
"VeryCloudy": [
' ',
'<span foreground=\"#585858\"; font-weight: bold;"> .--. </span>',
'<span foreground=\"#585858\"; font-weight: bold;"> .-( ). </span>',
'<span foreground=\"#585858\"; font-weight: bold;"> (___.__)__) </span>',
' '],
"LightShowers": [
'<span foreground=\"#FFFF00\"> _`/\'\'</span>"<span foreground=\"#BBBBBB\">.-. </span>',
'<span foreground=\"#FFFF00\"> ,\\_</span>"<span foreground=\"#BBBBBB\">( ). </span>',
'<span foreground=\"#FFFF00\"> /</span>"<span foreground=\"#BBBBBB\">(___(__) </span>',
'<span foreground=\"#87afff\";"> </span>',
'<span foreground=\"#87afff\";"> </span>'],
"HeavyShowers": [
'<span foreground=\"#FFFF00\"> _`/\'\'</span>"<span foreground=\"#585858\"; font-weight: bold;">.-. </span>',
'<span foreground=\"#FFFF00\"> ,\\_</span>"<span foreground=\"#585858\"; font-weight: bold;">( ). </span>',
'<span foreground=\"#FFFF00\"> /</span>"<span foreground=\"#585858\"; font-weight: bold;">(___(__) </span>',
'<span foreground=\"#0000ff\"; font-weight: bold;"> </span>',
'<span foreground=\"#0000ff\"; font-weight: bold;"> </span>'],
"LightSnowShowers": [
'<span foreground=\"#FFFF00\"> _`/\'\'</span>"<span foreground=\"#BBBBBB\">.-. </span>',
'<span foreground=\"#FFFF00\"> ,\\_</span>"<span foreground=\"#BBBBBB\">( ). </span>',
'<span foreground=\"#FFFF00\"> /</span>"<span foreground=\"#BBBBBB\">(___(__) </span>',
'<span foreground=\"#eeeeee\";"> * * * </span>',
'<span foreground=\"#eeeeee\";"> * * * </span>'],
"HeavySnowShowers": [
'<span foreground=\"#FFFF00\"> _`/\'\'</span>"<span foreground=\"#585858\"; font-weight: bold;">.-. </span>',
'<span foreground=\"#FFFF00\"> ,\\_</span>"<span foreground=\"#585858\"; font-weight: bold;">( ). </span>',
'<span foreground=\"#FFFF00\"> /</span>"<span foreground=\"#585858\"; font-weight: bold;">(___(__) </span>',
'<span foreground=\"#eeeeee\"; font-weight: bold;"> * * * * </span>',
'<span foreground=\"#eeeeee\"; font-weight: bold;"> * * * * </span>'],
"LightSleetShowers": [
'<span foreground=\"#FFFF00\"> _`/\'\'</span>"<span foreground=\"#BBBBBB\">.-. </span>',
'<span foreground=\"#FFFF00\"> ,\\_</span>"<span foreground=\"#BBBBBB\">( ). </span>',
'<span foreground=\"#FFFF00\"> /</span>"<span foreground=\"#BBBBBB\">(___(__) </span>',
'<span foreground=\"#87afff\";"> </span>"<span foreground=\"#eeeeee\";">*</span>"<span foreground=\"#87afff\";"> </span>"<span foreground=\"#eeeeee\";">* </span>',
'<span foreground=\"#eeeeee\";"> *</span>"<span foreground=\"#87afff\";"> </span>"<span foreground=\"#eeeeee\";">*</span>"<span foreground=\"#87afff\";"> </span>'],
"ThunderyShowers": [
'<span foreground=\"#FFFF00\"> _`/\'\'</span>"<span foreground=\"#BBBBBB\">.-. </span>',
'<span foreground=\"#FFFF00\"> ,\\_</span>"<span foreground=\"#BBBBBB\">( ). </span>',
'<span foreground=\"#FFFF00\"> /</span>"<span foreground=\"#BBBBBB\">(___(__) </span>',
'<span foreground=\"#ffff87\";"> \\</span>"<span foreground=\"#87afff\";"> </span>"<span foreground=\"#ffff87\";">\\</span>"<span foreground=\"#87afff\";"> </span>',
'<span foreground=\"#87afff\";"> </span>'],
"ThunderyHeavyRain": [
'<span foreground=\"#585858\"; font-weight: bold;"> .-. </span>',
'<span foreground=\"#585858\"; font-weight: bold;"> ( ). </span>',
'<span foreground=\"#585858\"; font-weight: bold;"> (___(__) </span>',
'<span foreground=\"#0000ff\"; font-weight: bold;"> </span>"<span foreground=\"#ffff87\";">\\</span>"<span foreground=\"#0000ff\";"></span>"<span foreground=\"#ffff87\";">\\</span>"<span foreground=\"#0000ff\";"> </span>',
'<span foreground=\"#0000ff\"; font-weight: bold;"> </span>"<span foreground=\"#ffff87\";">\\</span>"<span foreground=\"#0000ff\";"> </span>'],
"ThunderySnowShowers": [
'<span foreground=\"#FFFF00\"> _`/\'\'</span>"<span foreground=\"#BBBBBB\">.-. </span>',
'<span foreground=\"#FFFF00\"> ,\\_</span>"<span foreground=\"#BBBBBB\">( ). </span>',
'<span foreground=\"#FFFF00\"> /</span>"<span foreground=\"#BBBBBB\">(___(__) </span>',
'<span foreground=\"#eeeeee\";"> *</span>"<span foreground=\"#ffff87\";">\\</span>"<span foreground=\"#eeeeee\";">*</span>"<span foreground=\"#ffff87\";">\\</span>"<span foreground=\"#eeeeee\";">* </span>',
'<span foreground=\"#eeeeee\";"> * * * </span>'],
"LightRain": [
'<span foreground=\"#BBBBBB\"> .-. </span>',
'<span foreground=\"#BBBBBB\"> ( ). </span>',
'<span foreground=\"#BBBBBB\"> (___(__) </span>',
'<span foreground=\"#87afff\";"> </span>',
'<span foreground=\"#87afff\";"> </span>'],
"HeavyRain": [
'<span foreground=\"#585858\"; font-weight: bold;"> .-. </span>',
'<span foreground=\"#585858\"; font-weight: bold;"> ( ). </span>',
'<span foreground=\"#585858\"; font-weight: bold;"> (___(__) </span>',
'<span foreground=\"#0000ff\"; font-weight: bold;"> </span>',
'<span foreground=\"#0000ff\"; font-weight: bold;"> </span>'],
"LightSnow": [
'<span foreground=\"#BBBBBB\"> .-. </span>',
'<span foreground=\"#BBBBBB\"> ( ). </span>',
'<span foreground=\"#BBBBBB\"> (___(__) </span>',
'<span foreground=\"#eeeeee\";"> * * * </span>',
'<span foreground=\"#eeeeee\";"> * * * </span>'],
"HeavySnow": [
'<span foreground=\"#585858\"; font-weight: bold;"> .-. </span>',
'<span foreground=\"#585858\"; font-weight: bold;"> ( ). </span>',
'<span foreground=\"#585858\"; font-weight: bold;"> (___(__) </span>',
'<span foreground=\"#eeeeee\"; font-weight: bold;"> * * * * </span>',
'<span foreground=\"#eeeeee\"; font-weight: bold;"> * * * * </span>'],
"LightSleet": [
'<span foreground=\"#BBBBBB\"> .-. </span>',
'<span foreground=\"#BBBBBB\"> ( ). </span>',
'<span foreground=\"#BBBBBB\"> (___(__) </span>',
'<span foreground=\"#87afff\";"> </span>"<span foreground=\"#eeeeee\";">*</span>"<span foreground=\"#87afff\";"> </span>"<span foreground=\"#eeeeee\";">* </span>',
'<span foreground=\"#eeeeee\";"> *</span>"<span foreground=\"#87afff\";"> </span>"<span foreground=\"#eeeeee\";">*</span>"<span foreground=\"#87afff\";"> </span>'],
"Fog": [
' ',
'<span foreground=\"#c0c0c0\";"> _ - _ - _ - </span>',
'<span foreground=\"#c0c0c0\";"> _ - _ - _ </span>',
'<span foreground=\"#c0c0c0\";"> _ - _ - _ - </span>',
' '],
}
WEATHER_CODES_WEGO = {key: WEATHER_SYMBOL_WEGO[value] for key, value in WWO_CODE.items()}
data = {}
def format_time(time):
"""get the time formatted"""
return datetime.strptime(format_24_time(time), "%H").strftime("%I %p")
def format_24_time(time):
"""get the time formatted"""
return time.replace("00", "").zfill(2)
def format_temp(temp):
"""get the temp formatted"""
return (temp + "°").ljust(3)
def format_chances(hour):
"""get the chances formatted"""
chances = {
"chanceoffog": "Fog",
"chanceoffrost": "Frost",
"chanceofovercast": "Overcast",
"chanceofrain": "Rain",
"chanceofsnow": "Snow",
"chanceofsunshine": "Sunshine",
"chanceofthunder": "Thunder",
"chanceofwindy": "Wind",
}
conditions = []
for chance, event in chances.items():
if int(hour[chance]) > 0:
conditions.append(event + " " + hour[chance] + "%")
return ", ".join(conditions)
def build_text(current_condition):
"""build the text string"""
feels_like_f = current_condition["FeelsLikeF"]
weather_code = current_condition["weatherCode"]
tempint = int(feels_like_f)
extrachar = ""
if 0 < tempint < 10:
extrachar = "+"
current_weather = f"{WEATHER_CODES[weather_code]} {extrachar} {feels_like_f}°F"
return current_weather
def build_tooltip(current_condition, astronomy, moon_icon):
"""build the tooltip text"""
weather_description = current_condition['weatherDesc'][0]['value']
feels_like_f = current_condition["FeelsLikeF"]
temp_f = current_condition['temp_F']
humidity = current_condition['humidity']
wind_speed = current_condition['windspeedMiles']
wind_dir = current_condition['winddir16Point']
moon_phase = astronomy['moon_phase']
wego = WEATHER_CODES_WEGO[current_condition['weatherCode']]
tooltip = f"{wego[0]}{weather_description} {temp_f}°\n"
tooltip += f"{wego[1]}Feels like: {feels_like_f}°\n"
tooltip += f"{wego[2]}Wind: {wind_speed}mph {WIND_DIRECTION[wind_dir]}\n"
tooltip += f"{wego[3]}Humidity: {humidity}%\n"
tooltip += f"{wego[4]}Moon phase: {moon_phase} " + moon_icon + "\n"
return tooltip
def build_forecast(weather):
"""build a 3 day forecast"""
tooltip = "\n"
for i, day in enumerate(weather):
# determine day
if i == 0:
tooltip += "Today, "
if i == 1:
tooltip += "Tomorrow, "
# format the date
date = datetime.strptime(day['date'], "%Y-%m-%d").strftime("%a %b %d %Y")
tooltip += f"<b>{date}</b>\n"
# set the high and low
max_temp = day['maxtempF']
min_temp = day['mintempF']
tooltip += f" {max_temp}°F {min_temp}°F"
sunrise = day['astronomy'][0]['sunrise']
sunset = day['astronomy'][0]['sunset']
tooltip += f" {sunrise} {sunset}\n"
tooltip += build_hourly_forecast(i, day['hourly'], sunrise, sunset)
return tooltip
def build_hourly_forecast(day_num, hourly, sunrise, sunset):
"""build an hourly forecast"""
sunrise_hour = datetime.strptime(sunrise, "%I:%M %p").hour
sunset_hour = datetime.strptime(sunset, "%I:%M %p").hour
current_hour = datetime.now().hour
tooltip = ""
for hour in hourly:
time_24_hr = int(format_24_time(hour["time"]))
if day_num == 0:
if time_24_hr < current_hour - 2:
continue
# determine which code to use
if is_night_hour(time_24_hr, sunrise_hour, sunset_hour):
codes = WEATHER_CODES_WI_NIGHT
else:
codes = WEATHER_CODES_WI_DAY
current_time = format_time(hour['time'])
current_weather_code = codes[hour['weatherCode']]
feels_like = format_temp(hour['FeelsLikeF'])
weather_desc = hour['weatherDesc'][0]['value']
current_chances = format_chances(hour)
tooltip += f"{current_time} {current_weather_code} "
tooltip += f"{feels_like} {weather_desc}, {current_chances}\n"
return tooltip
def is_night_hour(time_24_hr, sunrise_hour, sunset_hour):
"""returns true if the hour is night"""
before_sunrise = time_24_hr < sunrise_hour
after_sunset = time_24_hr > sunset_hour
return after_sunset or before_sunrise
def get_wttr_json():
"""get the weather json"""
weather = requests.get("https://wttr.in/?u&format=j1", timeout=30).json()
moon = requests.get("https://wttr.in/?format=%m", timeout=30)
moon_icon = moon.text
current_condition = weather["current_condition"][0]
astronomy = weather["weather"][0]['astronomy'][0]
data["text"] = build_text(current_condition)
data["tooltip"] = build_tooltip(current_condition, astronomy, moon_icon)
data["tooltip"] += build_forecast(weather["weather"])
return json.dumps(data)
def main():
"""main"""
try:
print(get_wttr_json())
except Exception as e:
print(e)
main()
'';
in
{
home.packages = [ waybar-weather ];
}

View File

@@ -0,0 +1,99 @@
{ pkgs, hyprlandSettings, ... }:
let
settings = import ../../settings.nix { inherit pkgs; };
in
{
programs.wlogout = {
enable = true;
layout = {
lock = {
label = "lock";
action = "hyprlock --immediate";
text = "Lock";
keybind = "l";
};
hibernate = {
label = "hibernate";
action = "systemctl hibernate";
text = "Hibernate";
keybind = "h";
};
logout = {
label = "logout";
action = "sleep 1; hyprctl dispatch exit";
text = "Logout";
keybind = "e";
};
shutdown = {
label = "shutdown";
action = "systemctl poweroff";
text = "Shutdown";
keybind = "s";
};
suspend = {
label = "suspend";
action = "systemctl suspend";
text = "Suspend";
keybind = "u";
};
reboot = {
label = "reboot";
action = "reboot";
text = "Reboot";
keybind = "r";
};
};
style = ''
* {
background-image: none;
}
window {
background-color: ${settings.theme.nord.polarNight.nord0}f0
}
button {
margin: 8px;
color: ${settings.theme.nord.frost.nord7};
background-color: ${settings.theme.nord.polarNight.nord1};
border-style: solid;
border-width: 2px;
background-repeat: no-repeat;
background-position: center;
background-size: 25%;
}
button:active,
button:focus,
button:hover {
color: ${settings.theme.nord.frost.nord8};
background-color: ${settings.theme.nord.polarNight.nord2};
outline-style: none;
}
#lock {
background-image: image(url("icons/lock.png"));
}
#logout {
background-image: image(url("icons/logout.png"));
}
#suspend {
background-image: image(url("icons/suspend.png"));
}
#hibernate {
background-image: image(url("icons/hibernate.png"));
}
#shutdown {
background-image: image(url("icons/shutdown.png"));
}
#reboot {
background-image: image(url("icons/reboot.png"));
}
'';
};
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -0,0 +1,96 @@
{ pkgs, hyprlandSettings, ... }:
let
settings = import ../../settings.nix { inherit pkgs; };
in
{
programs.wofi = {
enable = true;
style = ''
* {
font-family: "${settings.fontName}", monospace;
font-size: 14px;
}
/* Window */
window {
margin: 0px;
padding: 10px;
border: 0.16em solid ${settings.theme.nord.aurora.nord15};
border-radius: 0.1em;
background-color: ${settings.theme.nord.polarNight.nord0};
}
/* Inner Box */
#inner-box {
margin: 5px;
padding: 10px;
border: none;
background-color: ${settings.theme.nord.polarNight.nord0};
}
/* Outer Box */
#outer-box {
margin: 5px;
padding: 10px;
border: none;
background-color: ${settings.theme.nord.polarNight.nord0};
}
/* Scroll */
#scroll {
margin: 0px;
padding: 10px;
border: none;
background-color: ${settings.theme.nord.polarNight.nord0};
}
/* Input */
#input {
margin: 5px 20px;
padding: 10px;
border: none;
border-radius: 0.1em;
color: ${settings.theme.nord.snowStorm.nord6};
background-color: ${settings.theme.nord.polarNight.nord0};
}
#input image {
border: none;
color: ${settings.theme.nord.aurora.nord11};
}
#input * {
outline: 4px solid ${settings.theme.nord.aurora.nord11}!important;
}
/* Text */
#text {
margin: 5px;
border: none;
color: ${settings.theme.nord.snowStorm.nord6};
}
#entry {
background-color: ${settings.theme.nord.polarNight.nord0};
}
#entry arrow {
border: none;
color: ${settings.theme.nord.aurora.nord15};
}
/* Selected Entry */
#entry:selected {
border: 0.11em solid ${settings.theme.nord.aurora.nord15};
}
#entry:selected #text {
color: ${settings.theme.nord.frost.nord7};
}
#entry:drop(active) {
background-color: ${settings.theme.nord.aurora.nord15}!important;
}
'';
};
}

View File

@@ -0,0 +1,173 @@
{ config, pkgs, lib, hyprlandSettings, ... }:
let
settings = import ./settings.nix { inherit pkgs; };
bing-wallpaper = pkgs.writeScriptBin "bing-wallpaper" ''
# Directory to store wallpapers
IMG_PATH="/run/wallpaper.jpg"
# Download if not already downloaded
URL=$(curl -s "https://www.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1" | \
jq -r '.images[0].url')
FULL_URL="https://www.bing.com$URL"
curl -s -o "$IMG_PATH" "$FULL_URL"
echo "Downloaded $FULL_URL to $IMG_PATH successfully"
'';
in
{
imports = [
./environment.nix
];
environment.systemPackages = [ bing-wallpaper pkgs.jq ];
home-manager.users."${settings.user}" = (import ./home.nix {inherit lib pkgs hyprlandSettings;});
services = {
displayManager = {
sddm = {
enable = true;
package = pkgs.kdePackages.sddm;
extraPackages = [ settings.sddm.package ];
theme = settings.sddm.themeName;
wayland.enable = true;
settings = {
Theme = {
ThemeDir = "${settings.sddm.package}/share/sddm/themes";
};
};
};
# Disable gdm
gdm.enable = lib.mkForce false;
defaultSession = "hyprland";
};
# disable other desktops
desktopManager = {
plasma6.enable = lib.mkForce false;
gnome.enable = lib.mkForce false;
};
dbus.enable = true;
ddccontrol.enable = true;
blueman.enable = true;
};
programs = {
hyprland = {
enable = true;
xwayland.enable = true;
portalPackage = pkgs.xdg-desktop-portal-hyprland;
};
nm-applet.enable = true;
};
systemd = {
services = {
preload-bing-wallpaper = {
enable = true;
wants = [ "network-online.target" ];
after = [ "network-online.target" ];
before = [ "display-manager.service" ];
requiredBy = [
"plymouth-quit-wait.service"
"display-manager.service"
];
wantedBy = [ "display-manager.service" ];
path = [
pkgs.bash
pkgs.jq
pkgs.curl
bing-wallpaper
];
script = ''
bing-wallpaper
'';
serviceConfig = {
Type = "oneshot";
};
};
};
user = {
services = {
reload-bing-wallpaper = {
enable = true;
path = [
pkgs.bash
pkgs.jq
pkgs.curl
pkgs.hyprland
bing-wallpaper
];
script = ''
bing-wallpaper
${pkgs.hyprland}/bin/hyprctl hyprpaper reload ,/run/wallpaper
'';
serviceConfig = {
Type = "oneshot";
};
};
};
# Create a timer to run the service periodically
timers = {
reload-bing-wallpaper = {
description = "Timer for reload-bing-wallpaper";
wantedBy = [ "timers.target" ];
# Timer configuration
timerConfig = {
OnCalendar = "daily"; # Check every day
Persistent = true; # Run immediately if last run was missed
Unit = "reload-bing-wallpaper.service";
};
};
};
};
extraConfig = ''
DefaultTimeoutStopSec=10s
'';
};
security = {
polkit.enable = true;
# configure sudo
sudo.extraRules = [
{
commands = [
{
command = "/run/current-system/sw/bin/waybar-weather";
options = [ "NOPASSWD" ];
}
{
command = "/run/current-system/sw/bin/waybar-updates";
options = [ "NOPASSWD" ];
}
];
groups = [ "wheel" ];
}
];
};
xdg.portal = {
enable = true;
wlr.enable = true;
xdgOpenUsePortal = true;
extraPortals = [
pkgs.xdg-desktop-portal-hyprland
pkgs.xdg-desktop-portal-gnome
pkgs.xdg-desktop-portal-gtk
];
};
nixpkgs.overlays = [
(self: super: {
waybar = super.waybar.overrideAttrs (oldAttrs: {
mesonFlags = oldAttrs.mesonFlags ++ [ "-Dexperimental=true" ];
});
})
];
}

View File

@@ -0,0 +1,62 @@
{ pkgs, ... }:
{
environment.systemPackages = with pkgs; [
box64
brightnessctl
ddcutil
dunst
egl-wayland
file-roller
glib
gnome-calculator
gnome-calendar
gnome-disk-utility
gnome-firmware
gnome-firmware-updater
gnome-font-viewer
gnome-logs
gnome-photos
gnome-tweaks
gnome-weather
gsettings-desktop-schemas
hyprcursor
hyprland
hyprpaper
hyprshot
hyprsysteminfo
kdePackages.qtmultimedia
libnotify
libz
mako
meson
nautilus
networkmanagerapplet
nm-tray
nwg-dock-hyprland
nwg-drawer
nwg-look
overskride
pamixer
pavucontrol
playerctl
polkit
polkit_gnome
qt5.qtwayland
qt6.qtwayland
rofi-wayland
waybar
wayland-protocols
wayland-utils
waypaper
wev
wl-clipboard
wlogout
wlroots
xdg-desktop-portal-hyprland
xdg-desktop-portal-gtk
xdg-desktop-portal-wlr
xorg.xhost
xsettingsd
xwayland
];
}

283
modules/nixos/hyprland/home.nix Executable file
View File

@@ -0,0 +1,283 @@
{ lib, pkgs, hyprlandSettings, ... }:
let
settings = import ./settings.nix { inherit pkgs hyprlandSettings; };
wallpaper = "/run/wallpaper.jpg";
jiggler = pkgs.python3.pkgs.buildPythonPackage rec {
pname = "jiggler";
version = "0.0.3";
format = "pyproject";
src = pkgs.fetchPypi {
inherit pname version;
sha256 = "sha256-6M4CbwxajYaQ5s73y+arKewLgu/pjfCay2giVVGYjhM=";
};
# do not run tests
doCheck = false;
nativeBuildInputs = with pkgs.python3.pkgs; [ setuptools ];
propagatedBuildInputs = with pkgs.python3.pkgs; [
click
pynput
];
};
in
{
imports = [
./config.nix
./config/btop
(import ./config/hypr {inherit pkgs hyprlandSettings;})
./config/kitty
./config/mako
(import ./config/waybar {inherit pkgs hyprlandSettings;})
./config/wofi
];
wayland.windowManager.hyprland = {
enable = true;
plugins = with pkgs.hyprlandPlugins; [
hyprgrass
];
settings = {
plugin = {
touch_gestures = {
# The default sensitivity is probably too low on tablet screens,
# I recommend turning it up to 4.0
sensitivity = "4.0";
# must be >= 3
workspace_swipe_fingers = "3";
# switching workspaces by swiping from an edge, this is separate from workspace_swipe_fingers
# and can be used at the same time
# possible values: l, r, u, or d
# to disable it set it to anything else
workspace_swipe_edge = "d";
# in milliseconds
long_press_delay = "400";
# resize windows by long-pressing on window borders and gaps.
# If general:resize_on_border is enabled, general:extend_border_grab_area is used for floating
# windows
resize_on_border_long_press = true;
# in pixels, the distance from the edge that is considered an edge
edge_margin = "10";
# emulates touchpad swipes when swiping in a direction that does not trigger workspace swipe.
# ONLY triggers when finger count is equal to workspace_swipe_fingers
#
# might be removed in the future in favor of event hooks
emulate_touchpad_swipe = false;
experimental = {
# send proper cancel events to windows instead of hacky touch_up events,
# NOT recommended as it crashed a few times, once it's stabilized I'll make it the default
send_cancel = "0";
};
hyprgrass-bind = [
# swipe left from right edge
", edge:r:l, workspace, +1"
# swipe up from bottom edge
", edge:d:u, exec, ${settings.defaultApps.browser.pname}"
# swipe down from left edge
", edge:l:d, exec, pactl set-sink-volume @DEFAULT_SINK@ -4%"
# swipe down with 4 fingers
", swipe:4:d, killactive"
# swipe diagonally left and down with 3 fingers
# l (or r) must come before d and u
", swipe:3:ld, exec, foot"
# tap with 3 fingers
", tap:3, exec, foot"
# longpress can trigger mouse binds:
", longpress:2, movewindow"
", longpress:3, resizewindow"
];
};
};
gestures = {
workspace_swipe = lib.mkForce true;
workspace_swipe_cancel_ratio = "0.15";
};
};
};
services = {
hyprpolkitagent.enable = true;
hyprpaper = {
enable = true;
settings = {
preload = [ "/run/wallpaper.jpg" wallpaper ];
wallpaper = hyprlandSettings.wallpaper;
splash = false;
};
};
hypridle = {
enable = true;
settings = {
general = {
before_sleep_cmd = "loginctl lock-session"; # lock before suspend.
after_sleep_cmd = "hyprctl dispatch dpms on"; # to avoid having to press a key twice to turn on the display.
ignore_dbus_inhibit = false;
lock_cmd = "pidof hyprlock || hyprlock"; # avoid starting multiple hyprlock instances.
};
listener = [
# {
# timeout = 300; # 5min
# on-timeout = "brightnessctl -s set 10"; # set monitor backlight to minimum, avoid 0 on OLED monitor.
# on-resume = "brightnessctl -r"; # monitor backlight restore.
# }
{
timeout = settings.lockScreenTimer;
on-timeout = "loginctl lock-session"; # lock screen when timeout has passed
}
{
timeout = settings.screenOffTimer;
on-timeout = "hyprctl dispatch dpms off"; # screen off when timeout has passed
on-resume = "hyprctl dispatch dpms on"; # screen on when activity is detected after timeout has fired.
}
{
timeout = settings.suspendTimer;
on-timeout = "systemctl suspend"; # suspend pc
}
];
};
};
};
programs = {
hyprlock = {
enable = true;
settings = {
background = [
{
monitor = "";
path = wallpaper; # supports png, jpg, webp (no animations, though)
color = "rgba(25, 20, 20, 1.0)";
# all these options are taken from hyprland, see https://wiki.hyprland.org/Configuring/Variables/#blur for explanations
blur_passes = "3"; # 0 disables blurring
blur_size = "7";
noise = "0.0117";
contrast = "0.8916";
brightness = "0.8172";
vibrancy = "0.1696";
vibrancy_darkness = "0.0";
}
];
input-field = [
{
size = "200, 50";
position = "0, -80";
monitor = hyprlandSettings.primaryDisplay.input;
dots_center = true;
fade_on_empty = true;
font_color = "rgb(202, 211, 245)";
inner_color = "rgb(91, 96, 120)";
outer_color = "rgb(24, 25, 38)";
bothlock_color = -1;
outline_thickness = 5;
placeholder_text = ''<span foreground="##cad3f5">Password...</span>'';
shadow_passes = 2;
}
];
};
};
vscode.profiles.default.userSettings."window"."titleBarStyle" = "custom";
};
home = {
sessionVariables = {
BROWSER = "${settings.defaultApps.browser.pname}";
CLUTTER_BACKEND = "wayland";
EDITOR = "${settings.defaultApps.editor.pname}";
VISUAL = "${settings.defaultApps.visual.pname}";
ICON_THEME = settings.iconTheme;
GTK_CSD = "0";
GTK_THEME = settings.gtkTheme;
GTK_USE_PORTAL = "1";
HYPRCURSOR_THEME = settings.cursorTheme;
HYPRCURSOR_SIZE = settings.cursorSize;
MOZ_ENABLE_WAYLAND = "1";
NIXOS_OZONE_WL = "1";
NIXOS_XDG_OPEN_USE_PORTAL = "1";
QT_AUTO_SCREEN_SCALE_FACTOR = "1";
QT_QPA_PLATFORM = "wayland-egl";
QT_QPA_PLATFORMTHEME = "gtk3";
QT_SCALE_FACTOR = "1";
QT_WAYLAND_DISABLE_WINDOWDECORATION = "1";
SDL_VIDEODRIVER = "wayland";
TERMINAL = "${settings.defaultApps.terminal.pname}";
XCURSOR_THEME = settings.cursorTheme;
XCURSOR_SIZE = settings.cursorSize;
XDG_CACHE_HOME = "\${HOME}/.cache";
XDG_CONFIG_HOME = "\${HOME}/.config";
XDG_CURRENT_DESKTOP = "Hyprland";
XDG_DATA_HOME = "\${HOME}/.local/share";
XDG_SESSION_DESKTOP = "Hyprland";
XDG_SESSION_TYPE = "wayland";
};
pointerCursor = {
gtk.enable = true;
package = settings.cursorThemePkg;
name = settings.cursorTheme;
size = settings.cursorSize;
};
packages = [
jiggler
] ++ settings.requiredPkgs;
};
dconf = {
enable = true;
settings = {
"org/gnome/desktop/interface".color-scheme = "prefer-dark";
"org/gnome/desktop/interface".cursor-theme = settings.cursorTheme;
"org/gnome/desktop/interface".gtk-theme = settings.gtkTheme;
"org/gnome/desktop/interface".icon-theme = settings.iconTheme;
};
};
gtk = {
enable = true;
cursorTheme = {
name = settings.cursorTheme;
package = settings.cursorThemePkg;
};
theme = {
name = settings.gtkTheme;
package = settings.gtkThemePkg;
};
iconTheme = {
name = settings.iconTheme;
package = settings.iconThemePkg;
};
gtk3.extraConfig = {
gtk-application-prefer-dark-theme = true;
};
gtk4.extraConfig = {
gtk-application-prefer-dark-theme = true;
};
font = {
name = settings.fontName;
package = settings.fontPackage;
size = settings.fontSize;
};
};
}

View File

@@ -0,0 +1,108 @@
{ pkgs, ... }:
let
nord = import ./theme.nix;
themeSize = "compact"; # [ "standard" "compact" ]
themeAccent = "all"; # [ "default" "purple" "pink" "red" "orange" "yellow" "green" "teal" "grey" "all" ]
themeVariant = "nord"; # [ "nord" "dracula" "gruvbox" "everforest" "catppuccin" "all" "black" "rimless" "normal" "float" ]
themeColor = "dark"; # [ "standard" "light" "dark" ]
iconThemeVariant = "all"; # [ "default" "purple" "pink" "red" "orange" "yellow" "green" "teal" "grey" "all" ]
iconScheme = "nord"; # [ "default" "nord" "dracula" "gruvbox" "everforest" "catppuccin" "all" ]
sddmThemePkg = pkgs.sddm-astronaut.override {
embeddedTheme = "astronaut";
themeConfig = {
Background = "/run/wallpaper.jpg";
};
};
in
{
# Username
user = "matt";
# Displays
displayLeft = {
input = "eDP-1";
resolution = "3456x2234"; # "3356x2160";
refreshRate = "60.00000";
};
displayRight = {
input = "DP-2";
resolution = "3840x2160";
refreshRate = "240.00000";
};
# Cursor
cursorTheme = "macOS";
cursorThemePkg = pkgs.apple-cursor;
cursorSize = 24;
# GTK
gtkThemeSize = themeSize;
gtkThemeAccent = themeAccent;
gtkThemeVariant = themeVariant;
gtkThemeColor = themeColor;
gtkTheme = "Colloid-Dark-Compact-Nord";
gtkThemePkg = pkgs.colloid-gtk-theme.override {
sizeVariants = [ themeSize ];
colorVariants = [ themeColor ];
themeVariants = [ themeAccent ];
tweaks = [ themeVariant ];
};
# Icons
iconThemeScheme = iconScheme;
iconTheme = "Colloid-Nord-Dark";
iconThemePkg = pkgs.colloid-icon-theme.override {
schemeVariants = [ iconScheme ];
colorVariants = [ iconThemeVariant ];
};
# Fonts
fontName = "JetBrainsMono NFM";
fontPackage = pkgs.nerd-fonts.jetbrains-mono;
fontSize = 12;
# SDDM/Locking
sddm = {
themeName = "sddm-astronaut-theme";
package = sddmThemePkg;
};
lockScreenTimer = 900; # 15 min
screenOffTimer = 930; # 15.5 min
suspendTimer = 3600; # 1hr
# Packages needed for the theme(s)
requiredPkgs = with pkgs; [
adwaita-icon-theme
adwaita-icon-theme
apple-cursor
catppuccin
catppuccin-gtk
catppuccin-qt5ct
catppuccin-sddm
colloid-gtk-theme
colloid-icon-theme
nemo
nemo-python
nemo-emblems
nemo-preview
nemo-seahorse
nemo-fileroller
nemo-qml-plugin-dbus
papirus-folders
sddm-astronaut
];
defaultApps = {
browser = pkgs.firefox;
editor = pkgs.micro;
fileExplorer = pkgs.nemo;
visual = pkgs.vscodium;
terminal = pkgs.kitty;
office = pkgs.onlyoffice-bin_latest;
video = pkgs.vlc;
imageViewer = pkgs.gnome-photos;
};
theme = nord;
}

View File

@@ -0,0 +1,7 @@
{ ... }:
{
specialisation.hyprland.configuration = {
imports = [ ./default.nix ];
environment.etc."specialisation".text = "hyprland";
};
}

View File

@@ -0,0 +1,66 @@
{
# Nord colors
# Opacity Hex alpha
# 100% FF
# 75% BF
# 50% 80
# 25% 40
# 10% 1A
# 0% 00
nord = {
polarNight = {
nord0 = "#2e3440";
nord1 = "#3b4252";
nord2 = "#434c5e";
nord3 = "#4c566a";
};
snowStorm = {
nord4 = "#d8dee9";
nord5 = "#e5e9f0";
nord6 = "#eceff4";
};
frost = {
nord7 = "#8fbcbb";
nord8 = "#88c0d0";
nord9 = "#81a1c1";
nord10 = "#5e81ac";
};
aurora = {
nord11 = "#bf616a";
nord12 = "#d08770";
nord13 = "#ebcb8b";
nord14 = "#a3be8c";
nord15 = "#b48ead";
};
};
waybar = {
defaultOpacity = "opacity: 0.85;";
defaultBorderRadius = "border-radius: 1rem;";
defaultCenterOptions = ''
padding-top: 0.2rem;
padding-bottom: 0.2rem;
padding-left: 0.5rem;
padding-right: 0.5rem;
margin: 3px 0;
'';
borderRight = ''
padding-top: 0.2rem;
padding-bottom: 0.2rem;
padding-left: 0.5rem;
padding-right: 0.5rem;
margin: 3px 0;
border-radius: 0rem 1rem 1rem 0rem;
margin-right: 0.5rem;
'';
borderLeft = ''
padding-top: 0.2rem;
padding-bottom: 0.2rem;
padding-left: 0.5rem;
padding-right: 0.5rem;
margin: 3px 0;
border-radius: 1rem 0rem 0rem 1rem;
margin-left: 0.5rem;
'';
};
}

View File

@@ -0,0 +1,39 @@
{ ... }:
{
# Set up impernance configuration for things like bluetooth
# In this configuration with /etc and /var/log being persistent, only directories outside of that need to be done here. See hardware configuration for all mountpoints.
environment.persistence."/nix/persist/system" = {
hideMounts = true;
directories = [
"/var/lib/bluetooth"
"/var/lib/iwd"
"/var/lib/nixos"
"/var/lib/libvirt"
"/var/lib/waydroid"
"/var/lib/systemd/coredump"
"/etc/NetworkManager/system-connections"
{
directory = "/var/lib/colord";
user = "colord";
group = "colord";
mode = "u=rwx,g=rx,o=";
}
{
directory = "/etc/nix";
user = "root";
group = "root";
mode = "u=rwx,g=rx,o=rx";
}
];
files = [
"/etc/machine-id"
];
};
security.sudo.extraConfig = ''
# rollback results in sudo lectures after each reboot
Defaults lecture = never
'';
}

View File

@@ -0,0 +1,58 @@
{
lib,
config,
pkgs,
...
}:
with lib;
let
cfg = config.share.hardware.nvidia;
in
{
imports = [ ./options.nix ];
config = mkIf cfg.enable {
hardware = {
# Nvidia
nvidia = {
package =
if cfg.enableBeta then
config.boot.kernelPackages.nvidiaPackages.beta
else
config.boot.kernelPackages.nvidiaPackages.latest;
# Modesetting is required.
modesetting.enable = true;
# Nvidia power management. Experimental, and can cause sleep/suspend to fail.
powerManagement.enable = true;
# Fine-grained power management. Turns off GPU when not in use.
# Experimental and only works on modern Nvidia GPUs (Turing or newer).
powerManagement.finegrained = false;
# Use the NVidia open source kernel module (not to be confused with the
# independent third-party "nouveau" open source driver).
# Support is limited to the Turing and later architectures. Full list of
# supported GPUs is at:
# https://github.com/NVIDIA/open-gpu-kernel-modules#compatible-gpus
# Only available from driver 515.43.04+
# Currently alpha-quality/buggy, so false is currently the recommended setting.
open = cfg.enableOpen;
# Enable the Nvidia settings menu,
# accessible via `nvidia-settings`.
nvidiaSettings = cfg.nvidiaSettings;
};
};
# Services configs
services.xserver = {
# Load nvidia driver for Xorg and Wayland
videoDrivers = [ "nvidia" ];
};
# Virtualisation
hardware.nvidia-container-toolkit.enable = cfg.enableNvidiaDocker;
};
}

View File

@@ -0,0 +1,27 @@
{ lib, ... }:
with lib;
{
options.share.hardware.nvidia = {
enable = mkEnableOption "nvidia hardware config";
enableOpen = mkOption {
type = types.bool;
default = false;
};
nvidiaSettings = mkOption {
type = types.bool;
default = false;
};
enableBeta = mkOption {
type = types.bool;
default = false;
};
enableNvidiaDocker = mkOption {
type = types.bool;
default = false;
};
};
}

58
modules/nixos/samba/default.nix Executable file
View File

@@ -0,0 +1,58 @@
{ lib, config, ... }:
with lib;
let
cfg = config.nas-samba;
in
{
imports = [ ./options.nix ];
config = mkIf cfg.enable {
# make shares visible for Windows clients
services.samba-wsdd = {
enable = true;
openFirewall = true;
};
services.netatalk = {
enable = cfg.enableTimeMachine;
settings = {
time-machine = {
path = cfg.timeMachinePath;
"valid users" = "whoever";
"time machine" = cfg.enableTimeMachine;
};
};
};
networking.firewall.enable = true;
networking.firewall.allowPing = true;
services.samba = {
enable = true;
openFirewall = true;
nsswins = true;
nmbd.enable = true;
settings =
let
make =
name: share:
nameValuePair "${name}" {
path = share.sharePath;
public = if share.enableTimeMachine then "no" else "yes";
browseable = if share.browseable then "yes" else "no";
writable = "yes";
"force group" = "jallen-nas";
"read only" = if share.readOnly then "yes" else "no";
"guest ok" = if share.guestOk then "yes" else "no";
"create mask" = share.createMask;
"directory mask" = share.directoryMask;
"fruit:aapl" = if share.enableTimeMachine then "yes" else "no";
"fruit:time machine" = if share.enableTimeMachine then "yes" else "no";
"vfs objects" = "catia fruit streams_xattr";
"fruit:time machine max size" = share.timeMachineMaxSize;
};
in
mapAttrs' make cfg.shares;
};
};
}

70
modules/nixos/samba/options.nix Executable file
View File

@@ -0,0 +1,70 @@
{ lib, ... }:
with lib;
{
options.nas-samba = {
enable = mkEnableOption "nas samba service";
autoStart = mkOption {
type = types.bool;
default = true;
};
enableTimeMachine = mkOption {
type = types.bool;
default = false;
};
timeMachinePath = mkOption {
type = types.str;
default = "";
};
hostsAllow = mkOption {
type = types.str;
default = "";
};
shares = mkOption {
type = types.attrsOf (
types.submodule {
options = {
public = mkOption {
type = types.bool;
default = false;
};
sharePath = mkOption {
type = types.str;
default = "";
};
readOnly = mkOption {
type = types.bool;
default = false;
};
browseable = mkOption {
type = types.bool;
default = true;
};
guestOk = mkOption {
type = types.bool;
default = true;
};
createMask = mkOption {
type = types.str;
default = "0774";
};
directoryMask = mkOption {
type = types.str;
default = "0775";
};
enableTimeMachine = mkOption {
type = types.bool;
default = false;
};
timeMachineMaxSize = mkOption {
type = types.str;
default = "0K";
};
};
}
);
default = { };
};
};
}

View File

@@ -0,0 +1,15 @@
{ lib, ... }:
{
programs = {
zsh.enable = lib.mkDefault true;
gnupg.agent = {
enable = lib.mkDefault true;
enableSSHSupport = lib.mkDefault true;
};
nix-index = {
enable = lib.mkDefault true;
enableBashIntegration = lib.mkDefault false;
enableZshIntegration = lib.mkDefault true;
};
};
}